【问题标题】:When is a Connection closed when calling JooQ DSLContext's .close(), if at all?调用 JooQ DSLContext 的 .close() 时连接何时关闭,如果有的话?
【发布时间】:2016-02-09 05:24:41
【问题描述】:

这是我正在编写的一个使用 JooQ 3.7.0 的类的代码(不相关的部分已被剥离);注意DSLContextAutoCloseable 功能的使用:

public final class JooqPerMethodMetricWriter
    implements PerMethodMetricWriter
{
    private static final Logger LOGGER
        = LoggerFactory.getLogger(JooqPerMethodMetricWriter.class);

    // [snip]

    private final DSLContext jooq;

    public JooqPerMethodMetricWriter(final Connection connection,
        final Instant instant)
        throws IOException
    {
        // [snip]    
        jooq = DSL.using(connection);    
    }

    private void writeCsv(final Configuration configuration)
    {
        // [snip]    

        try (
            final DSLContext context = DSL.using(configuration);
            final Reader reader = Files.newBufferedReader(csvPath);
        ) {

            final Loader<PermethodMetricsRecord> loader = context
                .loadInto(PERMETHOD_METRICS)
                .loadCSV(reader)
                .fields(PERMETHOD_METRICS.fields())
                .execute();
            LOGGER.info("{} lines stored in database", loader.stored());
        } catch (IOException e) {
            throw new RuntimeException("Cannot open CSV for reading", e);
        }
    // BREAKPOINT 1
    }

    @Override
    public void close()
        throws IOException
    {
        jooq.transaction(this::writeCsv);
        jooq.close();
        // BREAKPOINT 2
        Files.delete(csvPath);
    }
        // [snip]    
}

如果相关,使用的数据库是 PostgreSQL (9.4.x)。

在上面的代码中,我有两个断点。当我调试时,我看到:

  • 在第一个断点处,configuration.connectionProvider().acquire().isClosed() 为假...
  • 在第二个断点处, jooq.configuration().connectionProvider().acquire().isClosed() 也是错误的。

我很困惑。我作为构造函数参数收到的Connection 发生了什么?我需要自己.close()吗?


附带问题,这次是关于Loader:我保留默认值,因此.commitNone();鉴于我在事务中运行加载程序,如果我尝试使用 .commit&lt;somethingElse&gt;() 代替,例如 .commitAfter(1000),它会有所不同吗?

【问题讨论】:

  • 我可以请您在 Stack Overflow 上的一个单独问题中提出附带问题吗?它对未来的访问者会更有用...
  • @LukasEder 完成; here.

标签: java postgresql jooq


【解决方案1】:

当前答案

随着CloseableDSLContext 的引入,这个问题变得过时了,当时AutoCloseable 语义再次从更通用的DSLContext 中删除。 jOOQ 3.14 中实现了不兼容的更改,以解决此问题和其他一些问题中表达的混淆,请参阅:

https://github.com/jOOQ/jOOQ/issues/10512

历史答案

DSLContext 在 jOOQ 3.7 的 Java 8 发行版中变为 AutoCloseableDSLContext.close() 方法的 Javadoc 解释了这个 close() 调用的语义:

关闭底层资源,如果在构造这个DSLContext时已经分配了任何资源。

某些DSLContext 构造函数,例如DSL.using(String)DSL.using(String, Properties)DSL.using(String, String, String) 分配Connection 资源,DSLContext 实现的外部无法访问该资源。因此,必须通过close() 方法进行适当的资源管理。

只有在构建DSLContext 时分配的资源才会被释放。不是您传递给DSLContext 的资源。在您的情况下,您没有在此 try-with-resources 语句中分配任何资源,因此在它的末尾没有任何要发布的内容:

try (DSLContext context = DSL.using(configuration); ...) { ... }

如果您在此处分配一个新的Connection,情况会有所不同:

try (DSLContext context = DSL.using("jdbc:h2:~/test", "sa", ""); ...) { ... }

关于您的问题:

我很困惑。我作为构造函数参数收到的 Connection 发生了什么?

什么都没有。您必须自己管理其生命周期,因为 jOOQ 对您的连接生命周期策略一无所知。

我需要自己 .close() 吗?

是的。

【讨论】:

  • 好的,我应该更仔细地阅读 javadoc... 我可以建议“[...]如果在构造此 DSLContext 时分配了任何资源”以粗体显示并给出示例,例如,如果您使用匹配的.using() 方法,Connection 不会被关闭?
  • @fge:你是对的。更多示例在 Javadoc 中会很有用。我为此创建了一个问题:github.com/jOOQ/jOOQ/issues/4721
  • 那么另一个问题;我想在我的代码中,我不需要费心在TransactionalRunnable 中对创建的 DSLContext 进行 .close() 操作,对吧?
  • 呃,呃,等等,停下来……如果我使用了 `DSL.using(someJdbcUrl, someUser, somePassword),那么嵌入式 Configuration 呢?
  • 好吧,在这种情况下,我是否需要明确关闭我必须创建的嵌入式DSLContext?换句话说,外部上下文是否已经为我创建了连接并且我不需要关心它,还是会创建一个新的连接?
猜你喜欢
  • 2015-03-02
  • 2021-07-22
  • 2016-08-17
  • 2021-08-03
  • 2017-05-11
  • 2018-04-13
  • 1970-01-01
  • 2012-09-18
  • 2020-10-02
相关资源
最近更新 更多