[英]Differences in behaviour of REQUIRES_NEW and NESTED propagation in Spring transactions
Preface 前言
First of all: 首先:
It is not duplicate of Differences between requires_new and nested propagation in Spring transactions - I read it but I didn't found answer to my question 它与Spring事务中的requires_new和嵌套传播之间的差异不重复 - 我读了它,但我没有找到我的问题的答案
Question: 题:
After reading topic I mentioned I understood that main difference between propagation levels in count of physical transactions: 在阅读了我提到的主题之后,我理解了物理交易数量中传播水平的主要区别:
2 db transactions- for REQUIRES_NEW
for outer and for inner method 2 db事务 - 对于外部和内部方法的
REQUIRES_NEW
1 db transaction - for NESTED
for outer and for inner method. 1 db transaction - 用于
NESTED
for outer和for inner方法。 It will not work if underlying database doesn't support savepoints 如果底层数据库不支持保存点,它将无法工作
But looks like logic will be the same from my point if view. 但是看起来逻辑从我的观点来看是相同的。
How to understand which level to use in practise? 如何理解在实践中使用哪个级别? Any use cases to understand it?
任何用例了解它? Handy examples of behavioural differences?
方便的行为差异的例子?
PS PS
I suppose there are some visibility for other transactions differences because different transaction commit time. 我想其他事务差异有一些可见性,因为不同的事务提交时间。
PS2 PS2
Also I suppose there are performance difference: 另外我认为有性能差异:
@Transactional
public void outer(){
for(int i=0;i<100500;i++){
inner();
}
}
@Transactional
public void inner(){
//some logic
}
For that case NESTED will be better because of 1 long physical transaction instead of 100500+1 对于那种情况,NESTED会更好,因为1长的物理交易而不是100500 + 1
The big differences I see: 我看到的巨大差异:
in case of nested: 在嵌套的情况下:
In case of requires_new: 在requires_new的情况下:
In case of performance , if the other factors are not important, you can find a break even between transaction size and transaction number. 在性能方面 ,如果其他因素不重要,您可以在交易规模和交易数量之间找到收支平衡点。 imO there is no general answer to the question, if nested is faster than requires_new.
如果嵌套比requires_new快,那么问题没有一般的答案。
As it stands in your example, if inner()
had: 正如你的例子所示,如果
inner()
有:
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
//some logic
}
Then if it threw an exception from the second call in the outer()
loop, the changes from the first call would have already been committed - by its REQUIRES_NEW
. 然后,如果它从
outer()
循环中的第二个调用中抛出异常,则第一个调用的更改将已经由其REQUIRES_NEW
提交。
If inner()
had: 如果
inner()
有:
@Transactional(propagation=Propagation.NESTED)
public void inner(){
//some logic
}
Then the changes from the first call would be rolled back - because there is no catch block in outer()
. 然后将回滚第一次调用的更改 - 因为
outer()
没有catch块。
The point where the propagation level on inner()
really starts to matter is if the outer()
loop is going to handle exceptions in inner()
: 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
}
Clearly both REQUIRES_NEW
and NESTED
would only keep changes from the successful inner()
calls. 很明显,
REQUIRES_NEW
和NESTED
只会保留对成功的inner()
调用的更改。 The key difference though is that with NESTED
, there is still the option to throw it all away if there is a subsequent failure in outer()
. 但关键的区别在于,使用
NESTED
,如果outer()
存在后续故障,仍然可以选择将其全部丢弃。
As you say, the other factor is scalability - some databases may not appreciate the size of the parent transaction with NESTED
propagation. 如您所说,另一个因素是可伸缩性 - 某些数据库可能无法理解具有
NESTED
传播的父事务的大小。
Also, it might be worth saying - though I suspect it was just aiming for clarity in the example. 此外,它可能值得一说 - 尽管我怀疑它只是为了明确示例。 Calling
this.inner()
directly is bypassing the Spring transaction advisor. 直接调用
this.inner()
绕过Spring事务顾问。 It needs to be allowed to inject an 'advised bean' to allow the @Transactional
annotation to do its magic before and after the call - eg nextAutowiredBean.inner()
. 需要允许注入“建议的bean”以允许
@Transactional
注释在调用之前和之后执行其魔法 - 例如nextAutowiredBean.inner()
。
If your inner logic is independent of the outer logic then use Requires_new, if not use nested. 如果你的内部逻辑独立于外部逻辑,则使用Requires_new,如果不使用嵌套。
For example, your outer method may be processing a job containing a large number of records and calling an inner method that persists job status (progress, warnings and validation errors). 例如,您的外部方法可能正在处理包含大量记录的作业,并调用持久作业状态的内部方法(进度,警告和验证错误)。 You would want the inner methods transaction to be independent, and its db changes to be saved immediately so some other part of the system could display the progress.
您希望内部方法事务是独立的,并且其数据库更改将立即保存,以便系统的其他部分可以显示进度。 If the outer method encounters an exception, it's transaction would rollback, but the inner method's transactions would not.
如果外部方法遇到异常,它的事务将回滚,但内部方法的事务不会。
You would want to uses nested or dependent transactions when you need the outer and inner changes to either both be persisted or both be rolled back together. 当您需要对外部和内部更改进行持久化或同时回滚两者时,您可能希望使用嵌套或从属事务。 For example, you need to create a new user (using the "outer" service) and save their address (using the "inner" service).
例如,您需要创建一个新用户(使用“外部”服务)并保存其地址(使用“内部”服务)。 If your requirements are a user must have an address, then if the saving the user or address fails you want both changes to be rolled back.
如果您的要求是用户必须拥有地址,那么如果保存用户或地址失败,您希望回滚两个更改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.