java - Spring事务行为
问题描述
似乎当具有 NESTED 传播的事务弹簧方法调用另一个具有传播 REQUIRED 的事务方法时,内部事务可以强制回滚外部逻辑事务。任何人都可以确认吗?
我想处理 RuntimeException 而不是回滚外部事务,例如:
@Transactional
class A {
@Autowired
B b;
@Autowired
C c;
void methodA() { // outer transaction, this should not be rollback but currently getting UnexpectedRollbackException
b.methodB(() -> c.methodC());
}
}
@Transactional(propagation = Propagation.NESTED)
class B {
void methodB(Runnable action) { // inner nested transaction
try{
action.run();
} catch (Exception e){
// nothing
}
}
}
@Transactional
class C {
void methodC() { // inner required transaction
throw new RuntimeException();
}
}
解决方案
为什么不呢?NESTED
如果存在,则传播在当前交易中开始交易,REQUIRED
否则行为类似。javadocs 状态:
/**
* Support a current transaction; create a new one if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p>This is typically the default setting of a transaction definition,
* and typically defines a transaction synchronization scope.
*/
int PROPAGATION_REQUIRED = 0;
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
* feature in EJB.
* <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
* specific transaction managers. Out of the box, this only applies to the JDBC
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* when working on a JDBC 3.0 driver. Some JTA providers might support
* nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
int PROPAGATION_NESTED = 6;
值得注意的是,NESTED
仅当您的 JDBC 驱动程序支持保存点时才真正受支持。这表示:
没有现有交易 A(嵌套) B(必填)
会有以下行为:
begin; -- called prior to A but in A's
A.doSomething();
B.doSomethingThatCausesException()
rollback;
和
现有交易 A(嵌套) B(必填)
会有以下行为:
begin; -- called outside of the scope of A
savepoint A_savepoint
A.doSomething();
B.doSomethingThatCausesException();
rollback A_savepoint;
如果您的 JDBC 驱动程序支持嵌套事务。否则,它将表现得像第一个场景。另请参阅此答案。
也就是说,我相信保存点比它们的价值更麻烦,如果您以原子方式处理任何数据库操作,您将为自己节省很多潜在的麻烦。
推荐阅读
- swift - 在 Objective-C 中访问嵌套的 Swift 枚举
- vue.js - 使用 rest api 使用 vue js(Nuxt SSR) 创建一个管理面板。它安全吗?
- ios - 如何并行使用 Swift async/await
- bash - Bash 脚本 - 如何让它每 3 秒显示一次状态
- python - 错误找不到 QtWebEngineProcess.exe
- scala - Scala:不规则行为 foldleft() 与 foreach()
- android - 如何在 androidx 抽屉布局小部件中更改字体大小和颜色
- youtube - youtube 中的 yt、ytd、ytd-app 类型的 html 标签是什么?
- html - 如何使用 CSS 将每个单词的第一个字母大写我还尝试了其他股权溢出问题但没有奏效?
- python - 根据行值更改连接条件