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

JOOQ: Is a single statement implicitly transactional, or do I still have to wrap it in a transactional block?

假设我们在编写 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();

}

有以下说法:

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

  2. 第二个查询虽然已经执行且没有错误,但会在抛出异常时回滚。

正确吗?

最后,在以下情况下:

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

    throw new RuntimeException();
}

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

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

The first query will fail (at the latest) with a DataAccessException when executing the statement in the Database

正确

and roll back the entire statement

好吧,在事务回滚中没有 "roll back"。该语句刚刚失败

(no insert is committed).

正确(无论如何,语句本身没有提交任何内容)

The second query, although already executed without error, will be rolled back upon the exception being thrown.

正确。

the insert will be performed on the Database but will not be rolled back when the exception is thrown, because it is not in a transactional context.

正确。

have I misunderstood something?

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

使用 JDBC 自动提交

激活后:

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

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

没有JDBC自动提交

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

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