像许多旧数据库一样,Oracle具有旧数据类型,每天在SQL中都很难使用。 通常,您不再遇到LONG
和LONG RAW
数据类型的麻烦,但是当您使用旧数据库或词典视图时,您可能只需要处理LONG
。
这些数据类型与“较新的” LOB表示几乎相同:
-
LONG
和CLOB
有点相同,只是它们不是 -
LONG RAW
和BLOB
有点相同,只是它们不是
从JDBC读取LONG或LONG RAW会导致“流已关闭”异常
当您具有以下架构时:
CREATE TABLE t_long_raw_and_blob (
id NUMBER(7),
blob1 BLOB,
longx LONG RAW,
blob2 BLOB,
CONSTRAINT pk_t_long_raw_and_blob PRIMARY KEY (id)
);
CREATE TABLE t_long_and_clob (
id NUMBER(7),
clob1 CLOB,
longx LONG,
clob2 CLOB,
CONSTRAINT pk_t_long_and_clob PRIMARY KEY (id)
);
…您不能像这样简单地从JDBC(或其他API)中选择所有列:
try (PreparedStatement s = con.prepareStatement(
"SELECT * FROM t_long_raw_and_blob");
ResultSet rs = s.executeQuery()) {
while (rs.next()) {
System.out.println();
System.out.println("ID = " + rs.getInt(1));
System.out.println("BLOB1 = " + rs.getBytes(2));
System.out.println("LONGX = " + rs.getBytes(3));
System.out.println("BLOB2 = " + rs.getBytes(4));
}
}
如果执行上述操作,则会遇到以下类似问题:
Caused by: java.sql.SQLException: Stream has already been closed
at oracle.jdbc.driver.LongRawAccessor.getBytes(LongRawAccessor.java:162)
at oracle.jdbc.driver.OracleResultSetImpl.getBytes(OracleResultSetImpl.java:708)
... 33 more
相反,“正确”的解决方案是运行以下命令:
try (PreparedStatement s = con.prepareStatement(
"SELECT * FROM t_long_raw_and_blob");
ResultSet rs = s.executeQuery()) {
while (rs.next()) {
byte[] longx = rs.getBytes(3);
System.out.println();
System.out.println("ID = " + rs.getInt(1));
System.out.println("BLOB1 = " + rs.getBytes(2));
System.out.println("LONGX = " + longx);
System.out.println("BLOB2 = " + rs.getBytes(4));
}
}
简而言之:必须在所有其他列之前从ResultSet
检索所有LONG
或LONG RAW
列。
真讨厌
确实! 某种低级别的Oracle协议漏洞已泄漏到JDBC API外部,这是非常不幸的。 我们不在乎这些细节。 我们应该能够以任何顺序获取资源。
在jOOQ中, 我们已修复了#4820的问题 ,因此您可以运行语句并按希望的顺序对列进行排序:
DSL.using(configuration)
.select(
T_LONG_RAR_AND_BLOB.ID,
T_LONG_RAR_AND_BLOB.BLOB1,
T_LONG_RAR_AND_BLOB.LONGX,
T_LONG_RAR_AND_BLOB.BLOB2
)
.from(T_LONG_RAR_AND_BLOB)
.fetch();
从ResultSet
透明地获取列时,jOOQ将在内部对列进行重新排序。