LOBs являются PITA во всех базах данных, а также в JDBC. Правильная обработка занимает несколько строк кода, и вы можете быть уверены, что в конце концов ошибетесь. Потому что вы должны подумать о нескольких вещах:
- Прежде всего, большие объекты — это большие ресурсы, которые требуют особого управления жизненным циклом. После того, как вы выделили LOB, вам лучше «освободить» его, чтобы уменьшить нагрузку на ваш GC. Эта статья показывает больше о том, почему вам нужно освободить лоббов
- Время, когда вы выделяете и освобождаете долю, имеет решающее значение. Он может иметь более длительный срок службы, чем любой из ваших
ResultSet
,PreparedStatement
илиConnection
/ транзакции. Каждая база данных управляет такими периодами жизни индивидуально, и вам может потребоваться прочитать спецификации в крайних случаях - Хотя вы можете использовать
String
вместоClob
илиbyte[]
вместоBlob
для небольших и средних больших объектов, это не всегда так, и может даже привести к некоторым неприятным ошибкам, таким как страшный Oracle ORA-01461: может связать LONG значение только для вставки в столбец LONG
Итак, если вы работаете на низком уровне с использованием JDBC (вместо абстрагирования JDBC через Hibernate или jOOQ ), вам лучше написать небольшую утилиту, которая позаботится о правильной обработке больших объектов .
Недавно мы заново открыли нашу собственную утилиту, которую мы используем для тестирования интеграции jOOQ, по крайней мере, в некоторых базах данных, и подумали, что это может быть очень полезно для пары наших читателей, которые работают непосредственно с JDBC. Рассмотрим следующий класс:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
public class LOB implements AutoCloseable { private final Connection connection; private final List<Blob> blobs; private final List<Clob> clobs; public LOB(Connection connection) { this .connection = connection; this .blobs = new ArrayList<>(); this .clobs = new ArrayList<>(); } public final Blob blob( byte [] bytes) throws SQLException { Blob blob; // You may write more robust dialect // detection here if (connection.getMetaData() .getDatabaseProductName() .toLowerCase() .contains( "oracle" )) { blob = BLOB.createTemporary(connection, false , BLOB.DURATION_SESSION); } else { blob = connection.createBlob(); } blob.setBytes( 1 , bytes); blobs.add(blob); return blob; } public final Clob clob(String string) throws SQLException { Clob clob; if (connection.getMetaData() .getDatabaseProductName() .toLowerCase() .contains( "oracle" )) { clob = CLOB.createTemporary(connection, false , CLOB.DURATION_SESSION); } else { clob = connection.createClob(); } clob.setString( 1 , string); clobs.add(clob); return clob; } @Override public final void close() throws Exception { blobs.forEach(JDBCUtils::safeFree); clobs.forEach(JDBCUtils::safeFree); } } |
Этот простой класс имеет несколько приятных лакомств:
- Это
AutoCloseable
, так что вы можете освободить свои лобы с помощью оператора try-with-resources - Он абстрагируется от создания больших объектов на диалектах SQL. Не нужно помнить путь Oracle
Чтобы использовать этот класс, просто напишите что-то вроде следующего:
1
2
3
4
5
6
7
8
9
|
try ( LOB lob = new LOB(connection); PreparedStatement stmt = connection.prepareStatement( "insert into lobs (id, lob) values (?, ?)" ) ) { stmt.setInt( 1 , 1 ); stmt.setClob( 2 , lob.clob( "abc" )); stmt.executeUpdate(); } |
Это оно! Нет необходимости хранить ссылки на lob, безопасно освобождать его, если он не равен null, корректно восстанавливаться после исключений и т. Д. Просто поместите контейнер LOB
в оператор try-with-resources вместе с PreparedStatement
и готово.
Если вы заинтересованы в том, почему вы должны вызывать Clob.free()
или Blob.free()
, прочитайте нашу статью об этом . Это OutOfMemoryErrors
вас от одного или двух OutOfMemoryErrors
Ссылка: | Давайте рассмотрим, как вставить Clob или Blob через JDBC от нашего партнера по JCG Лукаса Эдера в блоге JAVA, SQL и AND JOOQ . |