Glassfish上的JDBC缓存

时间:2012-06-13 12:32:53

标签: jdbc glassfish

我在Glassfish的长期运行后台进程中遇到OutOfMemoryError。内存分析表明,在抛出错误时,50%的堆专用于com.mysql.JDBC4ResultSet(28.1%)和com.mysql.jdbc.StatementImpl(22.1%)的实例。

我的代码的结构是假设我的JDBC对象在松散范围后将被收集垃圾,但显然并非如此。我最初使用JPA做了这个,但内存负载爆炸,所以我恢复到JDBC,但我仍然得到巨大的内存泄漏,包括对JDBC语句的参考和结果集。

所以我想知道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
        }
    }
}

1 个答案:

答案 0 :(得分:2)

当您从实体管理器中解开连接并因此完全接管对您自己手中的资源的控制时,您应该在finally块中明确地关闭它们您自己与按照以下标准JDBC习语获取它们的try块完全相同。

// 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) {}
}

否则它们将保持打开状态,并且确实在服务器和数据库中泄漏。