Метод JDBC 4 java.sql.Clob.free() и обратная совместимость

Я исследую интересную проблему с производительностью, когда нет вызовов java.sql.Clob.free() на часто используемом ресурсе. Этот метод на Clob был представлен в Java 6/JDBC 4, так что вполне может быть, что на самом деле это регрессия, появившаяся при обновлении с JDBC 3 до JDBC 4.

Это известная проблема в драйвере Oracle JDBC? Можно ли сказать, что раньше Clobs каким-то волшебным образом освобождались, тогда как с JDBC 4 их ДОЛЖНО освобождать вручную? Или есть настройка драйвера, которую можно использовать для сохранения совместимости с JDBC 3?

Обратите внимание, то же самое относится и к Blob, конечно.


person Lukas Eder    schedule 13.03.2012    source источник


Ответы (2)


Наше приложение должно было обязательно вызывать java.sql.Clob.free() явно в oracle.sql.CLOB (используется toJdbc() для получения java.sql.Clob) с Oracle 11g и ojdbc6.jar (спецификация-версия «4.0» и «Версия реализации» «11.2.0.3.0» в MANIFEST.MF). В противном случае приложение страдало от существенных утечек памяти.

person user2457599    schedule 05.06.2013

Я просмотрел драйверы JDBC от поставщиков Oracle (ojdbc6.jar) для базы данных Oracle здесь
Я нашел файл demo.zip здесь
Я разархивировал его и проверил исходный код на наличие clob и blob.
Там есть файл TemporaryLobJDBC40.java
Там есть образец, в котором временные clob и blob создаются, а затем заполняются с некоторыми данными, а затем вставляется в таблицу с помощью подготовленного оператора (параметризованного INSERT).
Затем оператор выполняется, закрывается, временный объект clob и объект blob освобождаются, и транзакция фиксируется.

Затем автор перебирает строки таблицы, создавая постоянные BLOB-объекты и присваивая им объекты, возвращенные из 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();
  }
}
person Community    schedule 13.03.2012
comment
Спасибо за вашу помощь. Это убедительные признаки того, что я должен явно освободить свои clobs с помощью Java 6. Но мне действительно интересно получить авторитетный ответ о совместимости между ojdbc14 и ojdbc6... - person Lukas Eder; 14.03.2012
comment
Я могу разархивировать ojdbc6.jar и ojdbc14.jar, декомпилировать/разобрать соответствующие файлы .class и надеюсь получить приблизительный ответ. В настоящее время исходный код скрыт в файлах .class, и только автор или корпорация Oracle точно знают ответ. Было бы неплохо, если бы они проверяли этот сайт на наличие вопросов об их коде. На данный момент я бы посоветовал вам изменить свой код на явно свободные clobs и blobs. Это не так сложно с инструментами регулярных выражений. Если у вас есть файлы .class в вашем дереве зависимостей, и они предполагают неявную сборку мусора clob/blob, вы мало что можете сделать. - person ; 14.03.2012
comment
Это именно то, что я уже сделал. Тем не менее, хорошие вещи приходят к тем, кто ждет. Возможно, кто-то знает неопровержимые факты или уже спрашивал Тома раньше и опубликует ответ здесь... - person Lukas Eder; 14.03.2012