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:单个语句是隐式事务性的,还是我仍然必须将其包装在事务性块中?的主要内容,如果未能解决你的问题,请参考以下文章