JOOQ:单个语句是隐式事务性的,还是我仍然必须将其包装在事务性块中?

Posted

技术标签:

【中文标题】JOOQ:单个语句是隐式事务性的,还是我仍然必须将其包装在事务性块中?【英文标题】:JOOQ: Is a single statement implicitly transactional, or do I still have to wrap it in a transactional block? 【发布时间】:2017-05-06 14:34:49 【问题描述】:

假设我们在编写 JOOQ 查询时有以下场景:

insertInto(TABLE)
.set(TABLE.NAME, "...")
.set(TABLE.FK, null)  -- breaks FK constraint!
//...
.execute();

还有:

transactional(configuration -> 
    insertInto(TABLE)
    // list of sets that are OK
    .execute();

    throw new RuntimeException();


是以下语句:

    在数据库中执行语句并回滚整个语句(不提交插入)时,第一个查询将失败(最迟)并返回 DataAccessException

    第二个查询虽然已经正确执行,但会在抛出异常时回滚。

正确吗?

最后,在以下情况下:

 // non transactional code block
    insertInto(TABLE)
    // list of sets that are OK
    .execute();

    throw new RuntimeException();

插入将在数据库上执行,但在抛出异常时将不会回滚,因为它不在事务上下文中。

这都是正确的,还是我误解了什么?

【问题讨论】:

【参考方案1】:

在数据库中执行语句时,第一个查询将失败(最迟)并出现 DataAccessException

正确

并回滚整个语句

嗯,没有像事务回滚那样的“回滚”。声明失败了

(不提交插入)。

正确(在任何情况下,语句本身都没有提交任何内容)

第二个查询虽然已经正确执行,但会在抛出异常时回滚。

正确。

插入将在数据库上执行,但在抛出异常时不会回滚,因为它不在事务上下文中。

正确。

我是不是误会了什么?

是的。这与 jOOQ 并不严格相关,而是与一般的 SQL 语句相关。首先,JDBC 有一个自动提交模式,有时默认是激活的。

使用 JDBC 自动提交

当它处于活动状态时,则:

始终提交每个语句。 这意味着如果成功,该语句的更改将通过提交应用到数据库。 这也意味着如果它失败了,该语句将没有任何效果,因为它失败了。然而,仍然有一个提交。

请注意,自动提交是 JDBC 功能,而不是 jOOQ 功能。所以 jOOQ 继承了这里的 JDBC 设置。

没有 JDBC 自动提交

如果自动提交处于非活动状态,则每个新语句都将在 JDBC 中启动一个事务。当您使用 jOOQ 的 transaction() API 时,jOOQ 将覆盖 JDBC 自动提交标志以变为非活动状态并为您启动事务。现在,

如果您的Transactional 块/lambda 成功,则会发出提交。您的所有更改都会通过提交写入数据库。 如果您的Transactional 块/lambda 因异常而失败,则会发出回滚。您的所有更改都将通过回滚还原。 一个语句在提交时仍然需要成功才能生效

【讨论】:

很棒的信息,非常感谢!也很高兴了解 JDBC 自动提交,因为我以前没有遇到过。

以上是关于JOOQ:单个语句是隐式事务性的,还是我仍然必须将其包装在事务性块中?的主要内容,如果未能解决你的问题,请参考以下文章

在 Hibernate 事务中执行 jOOQ 语句

MySQL事务

为什么在C#中,引用型参数是隐式传递给函数的?

自动回滚多个语句的隐式事务?

DDL 语句总是给你一个隐式提交,还是你能得到一个隐式回滚?

SqlServer事务语法及使用方法