我正在调查一个有趣的性能问题,即在经常使用的资源上没有调用java.sql.Clob.free()
。 Clob
上的这个方法是在Java 6 / JDBC 4中引入的,所以很可能这实际上是从JDBC 3升级到JDBC 4时引入的回归。
这是Oracle JDBC驱动程序中的已知问题吗?可以说,之前,Clobs
以某种方式神奇地释放了自己,而使用JDBC 4,它们必须手动释放?或者是否有可用于与JDBC 3保持兼容的驱动程序设置?
注意,当然,这同样适用于Blob
。
答案 0 :(得分:5)
我们的应用程序必须确保在oracle.sql.CLOB上显式调用java.sql.Clob.free()(使用toJdbc()获取java.sql.Clob)与Oracle 11g和'ojdbc6.jar'(规范 - 版本'4.0'和实现 - 版本'11 .2.0.3.0'在MANIFEST.MF中)。否则应用程序会遭受大量内存泄漏。
答案 1 :(得分:1)
我查找了Oracle数据库here的Oracle供应商JDBC驱动程序(ojdbc6.jar)
我找到了demo.zip文件here
我拉开它并抓住clob和blob的来源
有一个文件TemporaryLobJDBC40.java
在那里,有一个示例,其中创建了temp clob和blob,然后填充了一些数据,然后通过准备好的语句(参数化INSERT)插入到表中。
然后,执行,关闭语句,释放temp clob和blob并提交事务。
然后,作者循环遍历表的行,创建永久blob / clobs,并为它们分配从getClob(),getBlob()返回的对象,并将内容转储到流中。
永久性的斑点永远不会被释放。我假设在每次迭代后,当对象超出范围时,垃圾收集器会自动释放这些对象。
在最后一次迭代之后,最后两个Blob / Clob对象没有被显式释放,但是被垃圾回收器(当它决定启动时)隐式清理它们的范围以最后一次迭代结束。 (在})之后
就个人而言,我会明确地进行清理,但是要对每个人进行清理。这个演示表明你可以 无论如何都要这样做。
这是代码(TemporaryLobJDBC40.java):
/*
* This sample shows how to create
* a temporary BLOB and CLOB, write
* some data to them and then insert
* them into a table. This makes a
* permanent copy in the table. The
* temp lobs are still available for
* further use if desired until the
* transaction is committed.
* When fetched from the table, the
* lobs are no longer temporary.
*
* This version uses the new
* JDBC 4.0 factory methods in
* java.sql.Connection and the
* free methods in java.sql.Blob and Clob
*
* Testing for temporary status still
* requires Oracle specfiic APIs in
* oracle.sql.BLOB and oracle.sql.CLOB.
*
* It needs jdk6 or later version and ojdbc6.jar
*/
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Blob;
import java.sql.Clob;
class TemporaryLobJDBC40
{
public static void main (String args [])
throws Exception
{
Connection conn = DemoConnectionFactory.getHRConnection( args );
LobExample.createSchemaObjects( conn );
Blob tempBlob = conn.createBlob();
Clob tempClob = conn.createClob();
System.out.println ("tempBlob.isTemporary()="+
((oracle.sql.BLOB)tempBlob).isTemporary());
System.out.println ("tempClob.isTemporary()="+
((oracle.sql.CLOB)tempClob).isTemporary());
LobExample.fill(tempBlob, 100L);
LobExample.fill(tempClob, 100L);
String insertSql = "insert into jdbc_demo_lob_table values ( ?, ?, ? )";
PreparedStatement pstmt = conn.prepareStatement( insertSql );
pstmt.setString( 1, "one" );
pstmt.setBlob( 2, tempBlob );
pstmt.setClob( 3, tempClob );
pstmt.execute();
pstmt.close();
tempBlob.free();
tempClob.free();
conn.commit();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery( "select b, c from jdbc_demo_lob_table" );
while( rs.next() )
{
Blob permanentBlob = rs.getBlob(1);
Clob permanentClob = rs.getClob(2);
System.out.println ("permanentBlob.isTemporary()="+
((oracle.sql.BLOB)permanentBlob).isTemporary());
System.out.println ("permanentClob.isTemporary()="+
((oracle.sql.CLOB)permanentClob).isTemporary());
LobExample.dump(permanentBlob);
LobExample.dump(permanentClob);
}
rs.close();
stmt.close();
conn.close();
}
}