如何在内部事务失败但内部事务应保存数据的情况下回滚外部事务 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.

调用的

解决方案-

  1. 您可以在事务设置中使用aspectj模式为内部方法启动新的事务。
  2. 将您的内部方法重构为另一个组件的一部分并标记 Propagation.REQUIRES_NEW
  3. 手动启动事务Programmatically start new transaction