JDBC 4的java.sql.Clob.free()方法和向后兼容性

时间:2012-03-13 13:00:53

标签: java oracle jdbc blob clob

我正在调查一个有趣的性能问题,即在经常使用的资源上没有调用java.sql.Clob.free()Clob上的这个方法是在Java 6 / JDBC 4中引入的,所以很可能这实际上是从JDBC 3升级到JDBC 4时引入的回归。

这是Oracle JDBC驱动程序中的已知问题吗?可以说,之前,Clobs以某种方式神奇地释放了自己,而使用JDBC 4,它们必须手动释放?或者是否有可用于与JDBC 3保持兼容的驱动程序设置?

注意,当然,这同样适用于Blob

2 个答案:

答案 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();
  }
}