Jooq 事务:如果事务中抛出异常,则连接不会释放到池中

Posted

技术标签:

【中文标题】Jooq 事务:如果事务中抛出异常,则连接不会释放到池中【英文标题】:Jooq transactions: connections are not released to pool, if exception thrown in transaction 【发布时间】:2018-03-06 19:40:56 【问题描述】:

我正在将 HikariCP 与 Jooq 一起使用。 代码: *在 Kotlin 中:

//dataSource is from Hikari
DSL.using(dataSource, sqlDialect).transaction 
     config ->
     //in create it simply calls dsl.insertInto .... 
     UserRepo.create(User(name="joe"), DSL.using(config))
     UserRepo.create(User(name="foo"), DSL.using(config))


一切正常。

但是如果我抛出块,连接不会关闭(释放)(尽管事务被回滚)。

更新:

我是 Java 新手,所以这是我的错。在测试中,我曾经抛出 Kotlin 的 Throwable(不是 Exception),它没有被 Java 部分代码正确处理。

常规异常情况下一切正常。

【问题讨论】:

【参考方案1】:

正如您所注意到的,鉴于您的问题编辑,jOOQ 在内部仅捕获 Exception 子类型,而不是 Throwable 子类型以影响事务管理。在DefaultDSLContext.transactionResult0() 中,您可以看到以下代码(取自版本 3.9.6,此问题的缩写):

try 
    provider.begin(ctx);
    result = transactional.run(ctx.configuration());
    provider.commit(ctx);

catch (Exception cause)  // <-- This is the problem
    ctx.cause(cause);
    provider.rollback(ctx);

    if (cause instanceof RuntimeException) 
        throw (RuntimeException) cause;
    
    else 
        throw new DataAccessException("Rollback caused", cause);
    

如您所见,虽然选中和未选中异常之间存在区别,但 ExceptionThrowable 之间没有区别。

基本原理,Java vs Kotlin / Scala

从历史上看,在 Java 中,没有人真正创建 Throwable 子类型。该类型仅作为ExceptionError 的通用超类型存在。因此,假设Throwable 是上述任何一种,并且Error 类型通常不应被任何客户端/库代码捕获。

这种假设在 Kotlin 和 Scala 等语言中无效,它们没有继承这一点,诚然,早期 Java 时代的 API 设计有点奇怪。用户定义的异常没有理由不直接扩展Throwable。不幸的是,现状意味着你不能使用 throwable,你必须抛出异常。

错误

这肯定是 jOOQ 中的一个错误,应该修复: https://github.com/jOOQ/jOOQ/issues/6608

由于它在行为方面有点向后不兼容,因此只会在次要版本中修复,即 3.10

【讨论】:

以上是关于Jooq 事务:如果事务中抛出异常,则连接不会释放到池中的主要内容,如果未能解决你的问题,请参考以下文章

Spring中@Transactional事务回滚

Transactional参数说明

Spring事务控制和回滚

spring事物回滚机制 (事务异常回滚,捕获异常不抛出就不会回滚)

使用 Jooq 进行集成测试

在 JOOQ 中,如果我直接使用底层连接,我的事务状态是不是保持不变?