AOP implements transactions: use try? C /atch wraps @Transactional annotated methods. If a method fails and meets certain criteria, the transaction can be rolled back in a catch. If there is no exception, the transaction can be committed.

“Certain conditions” include:

  • Only exceptions propagate out of the mark@TransactionalAnnotated method before the transaction can be rolled back. Spring has an invokeWithinTransaction method in TransactionAspectSupport, which is the logic to process the transaction. As you can see, subsequent transactions can proceed only if the exception is caught:

  • By default, Spring rolls back the transaction only when a RuntimeException or Error occurs.

Open Spring DefaultTransactionAttribute

  • The checked exception is usually a business exception or similar to the return value of another method. Such an exception may still complete the business, so it is not actively rolled back
  • Error or RuntimeException represents an unexpected result and should be rolled back

Cautionary tale

Registered Users:

  • CreateUserError1 throws a RuntimeException, but catch all exceptions within the method:

  • CreateUserError2, the registered user will have one at a timeotherTaskIf the file fails to be read, the registered DB operation is expected to be rolled back. CreateUserError2 (otherTask, createUserError2);

  • readFile

CreateUserError1; createUserError1; createUserError1;

Fix the bug

And how to verify the repair through logging. For the two cases, the corresponding repair methods are as follows.

1 If you want to catch exceptions and handle them, manually set the rollback state of the current office

@Transactional
public void createUserRight1(String name) {
    try {
        userRepository.save(new UserEntity(name));
        throw new RuntimeException("error");
    } catch (Exception ex) {
        log.error("create user failed", ex); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }}Copy the code

View the log, and the transaction confirms the rollback.

Transactional code has requested rollback: Manual rollback.

2 Declare in the annotations that the transaction is expected to be rolled back on all exceptions

To break the limit of not rolling back checked exceptions by default.

View logs, prompting rollback:

This case has DB operations, IO operations, and expects DB transactions to be rolled back in case of IO operation problems to ensure logical consistency.

summary

Because of incorrect exception handling, the transaction was in effect but was not rolled back when an exception occurred. Spring’s default is to roll back only @Transactional annotated methods when runtimeExceptions and errors occur, so if the method catches an exception, the transaction rollback needs to be handled by hand-written code. If you want Spring to rollback against other exceptions, configure the @Transactional annotation’s rollbackFor and noRollbackFor properties to override Spring’s default configuration.

Some businesses may contain multiple DB operations and do not necessarily want to treat the two operations as a single transaction, so you need to carefully consider the configuration of transaction propagation.