我使用 Oracle 11g(在 Red Hat 上)。我有一个带有 XMLType 列的简单常规表:
CREATE TABLE PROJECTS
(
PROJECT_ID NUMBER(*, 0) NOT NULL,
PROJECT SYS.XMLTYPE,
);
使用 Oracle SQL Developer(在 Windows 上)我这样做:
select T1.PROJECT P1 from PROJECTS T1 where PROJECT_ID = '161';
有用。我得到一个细胞。我可以双击并下载整个 XML 文件。
然后我尝试将结果作为 CLOB:
select T1.PROJECT.getClobVal() P1 from PROJECTS T1 where PROJECT_ID = '161';
有用。我得到一个细胞。我可以双击并查看整个文本并复制它。但有一个问题。当我将它复制到剪贴板时,我只得到前 4000 个字符。位置 4000 似乎有 0x00 字符,而 CLOB 的其余部分没有被复制。
为了确认这一点,我在 java 中编写了 check:
// ... create projectsStatement
Reader reader = projectsStatement.getResultSet().getCharacterStream( "P1" );
BufferedReader bf = new BufferedReader( reader );
char buffer[] = new char[ 1024 ];
int count = 0;
int globalPos = 0;
while ( ( count = bf.read( buffer, 0, buffer.length ) ) > 0 )
for ( int i = 0; i < count; i++, globalPos++ )
if ( buffer[ i ] == 0 )
throw new Exception( "ZERO at " + Integer.toString(globalPos) );
阅读器返回完整的 XML,但我的异常被抛出,因为位置 4000 有空字符。我可以删除这个单字节,但这将是一个相当奇怪的解决方法。
我在那里不使用 VARCHAR2 但也许这个问题与 VARCHAR2 限制(4000 字节)有关?还有其他想法吗?这是 Oracle 错误还是我遗漏了什么?
- - - - - - - - - - 编辑 - - - - - - - - - -
使用以下存储过程插入值:
create or replace
procedure addProject( projectId number, projectXml clob ) is
sqlstr varchar2(2000);
begin
sqlstr := 'insert into projects ( PROJECT_ID, PROJECT ) VALUES ( :projectId, :projectData )';
execute immediate sqlstr using projectId, XMLTYPE(projectXml);
end;
用于调用它的 Java 代码:
try ( CallableStatement cs = connection.prepareCall("{call addProject(?,?)}") )
{
cs.setInt( "projectId", projectId );
cs.setCharacterStream( "projectXml", new StringReader(xmlStr) , xmlStr.length() );
cs.execute();
}
- - - - - - - - - - 编辑。简单测试--------
我将使用我从你的答案中学到的一切。创建最简单的表:
create table T1 ( P XMLTYPE );
准备两个带有 XML 的 CLOB。第一个带有空字符,第二个没有。
declare
P1 clob;
P2 clob;
P3 clob;
begin
P1 := '<a>';
P2 := '<a>';
FOR i IN 1..1000 LOOP
P1 := P1 || '0123456789' || chr(0);
P2 := P2 || '0123456789';
END LOOP;
P1 := P1 || '</a>';
P2 := P2 || '</a>';
检查 null 是否在第一个 CLOB 中,而不是在第二个中:
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P1, chr(0) ) );
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P2, chr(0) ) );
我们会得到预期的:
14
0
尝试将第一个 CLOB 插入 XMLTYPE。不起作用。不能插入这样的值:
insert into T1 ( P ) values ( XMLTYPE( P1 ) );
尝试将第二个 CLOB 插入 XMLTYPE。它将起作用:
insert into T1 ( P ) values ( XMLTYPE( P2 ) );
尝试将插入的 XML 读入第三个 CLOB。它将起作用:
select T.P.getClobVal() into P3 from T1 T where rownum = 1;
检查是否有空。没有空值:
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P3, chr(0) ) );
似乎数据库内部没有空值,只要我们在 PL/SQL 上下文中,就没有空值。但是,当我尝试在 SQL Developer(在 Windows 上)或 Java(在 Red Hat EE 和 Tomcat7 上)中使用以下 SQL 时,我在所有返回的 CLOB 中的位置 4000 处得到空字符:
select T.P.getClobVal() from T1 T;
BR,JM