Как и многие старые базы данных, Oracle имеет устаревшие типы данных, с которыми довольно сложно работать в повседневной SQL. Обычно вы больше не сталкиваетесь с типами данных LONG
и LONG RAW
, но когда вы работаете со старой базой данных или представлениями словаря, вам, возможно, придется иметь дело с LONG
.
Эти типы данных в значительной степени совпадают с «более новыми» представлениями больших объектов:
-
LONG
иCLOB
— это несколько одно и то же, за исключением того, что -
LONG RAW
иBLOB
— это одно и то же, за исключением того, что
Чтение LONG или LONG RAW из JDBC вызывает исключение «Поток уже закрыт»
Когда у вас есть следующая схема:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
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) следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
|
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)); } } |
Если вы делаете выше, вы столкнетесь с чем-то вроде:
1
2
3
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 |
«Правильным» решением было бы выполнить следующее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
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)); } } |
Вкратце: все столбцы LONG
или LONG RAW
должны быть получены из ResultSet
до всех остальных столбцов.
Это противно
Верно! Какой-то недостаток протокола Oracle низкого уровня просочился за пределы JDBC API, что очень прискорбно. Мы не заботимся об этих деталях. Мы должны иметь возможность получать ресурсы в любом порядке.
В jOOQ мы исправили эту проблему # 4820 , поэтому вы можете запустить свое утверждение и упорядочить столбцы в любом порядке:
1
2
3
4
5
6
7
8
9
|
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 (); |
jOOQ будет внутренне переупорядочивать столбцы при извлечении их из ResultSet
, прозрачно.
Ссылка: | Oracle LONG и LONG RAW Вызывает «Поток уже закрыт» Исключение от нашего партнера JCG Лукаса Эдера в блоге JAVA, SQL и AND JOOQ . |