2012-06-13 34 views
1

在Glassfish上長時間運行的後臺進程中,我遇到了OutOfMemoryError。內存分析表明,在錯誤發生時,50%的堆專用於com.mysql.JDBC4ResultSet(28.1%)和com.mysql.jdbc.StatementImpl(22.1%)的實例。Glassfish上的JDBC緩存

我的代碼的結構是假設我的JDBC對象一旦鬆動範圍就會被垃圾收集,但顯然不是這種情況。我原本是使用JPA做的,但是內存負載爆炸了,所以我恢復到了JDBC,但是我仍然收到巨大的內存泄漏,其中包含對JDBC語句& ResultSets的引用。

所以我想知道如果Glassfish緩存這些查詢,我怎麼可以禁用,數據對象是相當大的,我真的不需要它們被緩存。

我在下面包含了我的代碼的結構,它由一個類和兩個方法組成(爲了簡潔而修改)。

@Stateless 
public class WSDFileCollector implements Collector { 

    @PersistenceContext 
    private EntityManager em; 

    @Override 
    @Asynchronous 
    public void run(final CollectorEntity collector) throws SQLException { 

     final Connection connection = em.unwrap(Connection.class); 
     final String table = "tmp_sat_" + collector.getSite().getId(); 
     final String column = "filename"; 
     try { 
      // Create temporary table 
      // Scan files & folders under a given directory. 
      // Load filenames into MySQL Temporary table. 

      final Statement statement = connection.createStatement(); 
      final ResultSet results = statement.executeQuery("SELECT filename FROM temporary_table WHERE filename NOT IN (SELECT filename FROM existing_files"); 
      while (results.next()) { 
       final File file = new File(collector.getPath(), results.getString("filename")); 
       if (file.isFile()) { 
        extractAndSave(file, collector); 
       } 
      } 
     } finally { 
      // Delete temporary table 
     } 
    } 

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    private void extractAndSave(final File file, final CollectorEntity collector) { 
     final Connection connection = em.unwrap(Connection.class); 
     try { 
      // Begin a transaction 
      // INSERT new file into existing_files 

      // Scan the file, extract data and insert into multiple database tables. 

      // Commit transaction 
     } catch (final SQLException | FileNotFoundException ex) { 
      // Rollback transaction 
     } 
    } 
} 

回答

2

正如你解開從實體管理器的連接,從而完全接管了在你自己的手中的資源控制,你應該明確自己關閉它們在非常相同的tryfinally塊塊按照以下標準JDBC慣用法獲取它們的位置。

// Declare resources. 
Connection connection = null; 
Statement statement = null; 
ResultSet resultSet = null; 

try { 
    // Acquire resources. 
    connection = getConnectionSomehow(); 
    statement = connection.createStatement(); 
    resultSet = statement.executeQuery(sql); 

    // ... 
} finally { 
    // Close resources in reversed order. 
    if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {} 
    if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {} 
    if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {} 
} 

否則,它們將保持在打開狀態,確實泄漏掉在服務器和數據庫兩者。

+0

你的錢一如既往BalusC。我不知道ResultSet和Statement需要關閉。謝謝。 – klonq

+0

不客氣。 – BalusC