简体   繁体   English

如果内部事务失败但内部事务应该保存数据,如何回滚外部事务

[英]How to rollback outer transaction in case of failed inner transaction in but inner transaction should save data Spring

Trying to prevent rollback of inner transactions. 试图防止内部事务回滚。 if inner transactions response not SUCCESS then outer transactions should rollback but inner transaction should save data. 如果内部事务响应不成功,则外部事务应回滚,但内部事务应保存数据。

@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;
}

Configure the inner transactional method as Propagation.REQUIRES_NEW such that it will always commit (ie save the data) when the method completes whether the outer transactional method rollbacks or not. 将内部事务方法配置为Propagation.REQUIRES_NEW ,以便无论外部事务方法是否回滚,该方法完成时它将始终提交(即保存数据)。

Also, make sure outer method does not self invocation the inner method as @Transactional does not work in this case (See Method visibility and @Transactional section in docs ). 另外,请确保外部方法不会自我调用内部方法,因为@Transactional在这种情况下不起作用(请参阅docs中的方法可见性和@Transactional部分)。

They should reside in different beans which the outer method calls the bean of the inner method: 它们应该驻留在外部方法调用内部方法的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 is ignored for your Test2 method and the call is part of single transaction. @Transactional被忽略你Test2方法和调用单个事务的一部分。

two things to consider here as Spring doc says - 正如Spring文档所说的,这里有两件事要考虑-

Method visibility and @Transactional 方法可见性和@Transactional

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. 使用代理时,应仅将@Transactional注释应用于具有公共可见性的方法。 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. 如果使用@Transactional注释对受保护的,私有的或程序包可见的方法进行注释,则不会引发任何错误,但是带注释的方法不会显示已配置的事务设置。 Consider the use of AspectJ (see below) if you need to annotate non-public methods. 如果需要注释非公共方法,请考虑使用AspectJ(请参见下文)。

Proxy mode 代理模式

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. 这意味着自调用实际上是目标对象中调用目标对象另一个方法的方法,即使调用的方法标记有@Transactional,也不会在运行时导致实际事务。

If you want to save data for inner method you can choose to start new Transaction for Test2 method so it does not impact existing transaction started by Test1 . 如果要保存内部方法的数据,则可以选择为Test2方法启动新的Transaction,这样就不会影响Test1启动的现有事务。

But it will not start the new Transaction in your case even if you make Test2 public cuase its called from the same class. 但是,即使您公开Test2从同一个类调用它,也不会在您的情况下启动新事务。

Solution - 解决方案-

  1. You can use aspectj mode in transaction settings to start new transaction for inner method. 您可以在事务设置中使用Aspectj模式来为内部方法启动新事务。
  2. Refactor your inner method to be part of another component and mark Propagation.REQUIRES_NEW 将内部方法重构为另一个组件的一部分,并标记Propagation.REQUIRES_NEW
  3. manually start the transaction Programmatically start new transaction 手动启动事务以编程方式启动新事务

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM