LOB是所有数据库以及JDBC中的PITA。 正确处理它们需要花费几行代码,并且可以确保最终会出错。 因为您必须考虑以下几点:
- 首先,LOB是繁重的资源,需要特殊的生命周期管理。 分配LOB后,最好“释放”它,以减轻GC的压力。 本文详细介绍了为什么需要释放吊球
- 分配和释放吊球的时间至关重要。 它的寿命可能比
ResultSet
,PreparedStatement
或Connection
/ Transactions中的任何一个都更长。 每个数据库都单独管理这样的生命周期,在极端情况下,您可能必须阅读规格 - 对于中小型LOB,您可以使用
String
而不是Clob
或byte[]
代替Blob
,但这可能并非总是如此,甚至可能会导致一些令人讨厌的错误,例如Oracle可怕的ORA-01461:可以绑定LONG值仅用于插入LONG列
因此,如果您正在使用JDBC进行低级工作(而不是通过Hibernate或jOOQ来抽象JDBC),则最好编写一个小工具来妥善处理LOB。
最近,我们至少在某些数据库中重新发现了我们用于jOOQ集成测试的实用程序,并认为这对于直接使用JDBC的一些读者可能非常有用。 考虑以下类别:
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方言创建LOB的过程。 无需记住Oracle的方式
要使用此类,只需编写如下内容:
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
容器与PreparedStatement
一起放入try-with-resources语句中即可。
如果您对为什么必须首先调用Clob.free()
或Blob.free()
,请阅读有关它的文章 。 它将为您OutOfMemoryErrors
一两个OutOfMemoryErrors
翻译自: https://www.javacodegeeks.com/2015/04/lets-review-how-to-insert-clob-or-blob-via-jdbc.html