简体   繁体   中英

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.

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 ).

They should reside in different beans which the outer method calls the bean of the inner method:

@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.

two things to consider here as Spring doc says -

Method visibility and @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.

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.

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 .

But it will not start the new Transaction in your case even if you make Test2 public cuase its called from the same class.

Solution -

  1. You can use aspectj mode in transaction settings to start new transaction for inner method.
  2. Refactor your inner method to be part of another component and mark Propagation.REQUIRES_NEW
  3. manually start the transaction Programmatically start new transaction

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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