如何在内部事务失败但内部事务应保存数据的情况下回滚外部事务 Spring
How to rollback outer transaction in case of failed inner transaction in but inner transaction should save data Spring
正在尝试防止内部事务回滚。如果内部事务响应不成功,则外部事务应回滚,但内部事务应保存数据。
@Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)
private void test1(Account account) throws Exception {
DOA.save(account);
status = test2(account);
if(status!='SUCCESS'){
throw new Exception("api call failed");
}
}
@Transactional(propagation=Propagation.MANDATORY)
private void test2(Account account) {
response //API Call
DOA.save(response);
return response.status;
}
将内部事务方法配置为 Propagation.REQUIRES_NEW
,这样无论外部事务方法是否回滚,它都会在方法完成时始终提交(即保存数据)。
此外,确保外部方法不会自行调用内部方法,因为 @Transactional
在这种情况下不起作用(参见 docs 中的方法可见性和 @Transactional 部分)。
它们应该驻留在外部方法调用内部方法的 bean 的不同 bean 中:
@Service
public class Service1 {
@Autowired
private Service2 service2;
@Transactional(rollbackFor=Exception.class)
public void test1(Account account) throws Exception {
DOA.save(account);
status = service2.test2(account);
if(status!='SUCCESS'){
throw new Exception("Api call failed");
}
}
}
@Service
public class Service2{
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void test2(Account account) {
response // API Call
DOA.save(response);
return response.status;
}
}
@Transactional
被您的 Test2
方法忽略,调用是单个事务的一部分。
这里要考虑两件事 Spring 医生说 -
方法可见性和@Transactional
When using proxies, you should apply the @Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the @Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings. Consider the use of AspectJ (see
below) if you need to annotate non-public methods.
代理模式
In proxy mode (which is the default), only external method calls
coming in through the proxy are intercepted. This means that
self-invocation, in effect, a method within the target object calling
another method of the target object, will not lead to an actual
transaction at runtime even if the invoked method is marked with
@Transactional.
如果您想为内部方法保存数据,您可以选择为 Test2
方法启动新事务,这样它就不会影响由 Test1
启动的现有事务。
但它不会在你的情况下启动新的交易,即使你Test2
public 因为它是从同一个 class.
调用的
解决方案-
- 您可以在事务设置中使用aspectj模式为内部方法启动新的事务。
- 将您的内部方法重构为另一个组件的一部分并标记
Propagation.REQUIRES_NEW
- 手动启动事务Programmatically start new transaction
正在尝试防止内部事务回滚。如果内部事务响应不成功,则外部事务应回滚,但内部事务应保存数据。
@Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)
private void test1(Account account) throws Exception {
DOA.save(account);
status = test2(account);
if(status!='SUCCESS'){
throw new Exception("api call failed");
}
}
@Transactional(propagation=Propagation.MANDATORY)
private void test2(Account account) {
response //API Call
DOA.save(response);
return response.status;
}
将内部事务方法配置为 Propagation.REQUIRES_NEW
,这样无论外部事务方法是否回滚,它都会在方法完成时始终提交(即保存数据)。
此外,确保外部方法不会自行调用内部方法,因为 @Transactional
在这种情况下不起作用(参见 docs 中的方法可见性和 @Transactional 部分)。
它们应该驻留在外部方法调用内部方法的 bean 的不同 bean 中:
@Service
public class Service1 {
@Autowired
private Service2 service2;
@Transactional(rollbackFor=Exception.class)
public void test1(Account account) throws Exception {
DOA.save(account);
status = service2.test2(account);
if(status!='SUCCESS'){
throw new Exception("Api call failed");
}
}
}
@Service
public class Service2{
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void test2(Account account) {
response // API Call
DOA.save(response);
return response.status;
}
}
@Transactional
被您的 Test2
方法忽略,调用是单个事务的一部分。
这里要考虑两件事 Spring 医生说 -
方法可见性和@Transactional
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
代理模式
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.
如果您想为内部方法保存数据,您可以选择为 Test2
方法启动新事务,这样它就不会影响由 Test1
启动的现有事务。
但它不会在你的情况下启动新的交易,即使你Test2
public 因为它是从同一个 class.
解决方案-
- 您可以在事务设置中使用aspectj模式为内部方法启动新的事务。
- 将您的内部方法重构为另一个组件的一部分并标记
Propagation.REQUIRES_NEW
- 手动启动事务Programmatically start new transaction