序言
首先:
它不是Activating a state的副本-我读了它,但没有找到我的问题
的答案问题:
在阅读了主题之后,我提到我了解到传播级别之间的主要区别在于物理交易:
2个数据库事务-用于REQUIRES_NEW
的外部方法和内部方法
1 db事务-用于NESTED
的外部方法和内部方法。如果基础数据库不支持保存点,它将无法正常工作
但是,从我的角度来看,如果逻辑上看来,逻辑将是相同的。
如何理解在实践中使用哪个级别?有什么用例可以理解吗?方便的行为差异例子?
PS
我想其他交易差异有一些可见性,因为不同的交易提交时间。
P.S.2
我还认为它们之间存在性能差异:
@Transactional
public void outer(){
for(int i=0;i<100500;i++){
inner();
}
}
@Transactional
public void inner(){
//some logic
}
在这种情况下,NESTED会更好,因为需要进行1次长时间的物理交易,而不是100500 + 1
答案 0 :(得分:3)
在您的示例中,如果inner()
具有:
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
//some logic
}
然后,如果它从outer()
循环中的第二次调用引发了异常,则从第一次调用开始的更改将已经由REQUIRES_NEW
提交。
如果inner()
有:
@Transactional(propagation=Propagation.NESTED)
public void inner(){
//some logic
}
然后,由于第一个调用中的更改将被回滚-因为outer()
中没有catch块。
inner()
上的传播级别真正开始起作用的点是outer()
循环是否要处理inner()
中的异常:
@Transactional
public void outer() {
for (int i = 0; i < 100500; i++) {
try {
inner();
} catch (Exception ex) {
// Report and continue
}
}
// Something else that could fail
}
很显然,REQUIRES_NEW
和NESTED
只会保留成功的inner()
调用中的更改。尽管关键的区别在于,NESTED
的使用仍然存在选择,如果outer()
随后发生故障,则可以将其全部丢弃。
正如您所说,另一个因素是可伸缩性-一些数据库可能不了解NESTED
传播时父事务的大小。
另外,也许值得一说-尽管我怀疑它只是为了使示例清晰。直接调用this.inner()
会绕过Spring事务顾问。需要允许它注入“建议的bean”,以使@Transactional
注释在调用之前和之后都可以发挥其魔力-例如, nextAutowiredBean.inner()
。
答案 1 :(得分:2)
我看到的巨大差异:
如果嵌套:
如果是require_new:
如果性能,如果其他因素不重要,则可以在交易规模和交易数量之间找到收支平衡。 i.m.O,如果嵌套比require_new快,那么这个问题没有一般性的答案。
答案 2 :(得分:1)
如果内部逻辑独立于外部逻辑,则使用Requires_new(如果不使用嵌套)。
例如,您的外部方法可能是在处理包含大量记录的作业,然后调用一个内部方法来保留作业状态(进度,警告和验证错误)。您可能希望内部方法事务是独立的,并且其db更改应立即保存,以便系统的其他部分可以显示进度。如果外部方法遇到异常,则其事务将回滚,而内部方法的事务将不回滚。
当您需要外部和内部更改同时保留或全部回滚时,您可能希望使用嵌套或相关事务。例如,您需要创建一个新用户(使用“外部”服务)并保存其地址(使用“内部”服务)。如果您的要求是用户必须有一个地址,那么如果保存该用户或地址失败,则希望两个更改都回滚。