Spring: automatic rollback on checked exceptions

Viewed 8681

One way to configure Spring to rollback on a non RuntimeExceptions is using @Transactional(rollbackFor=...) annotation on the service classes. The problem with this approach is that we need to define (rollbackFor=...) for almost all the service classes which seems really redundant.


My question: Is there any way to configure a default behaviour for Spring transaction manager to rollback on a non RuntimeException whenever it happens without declaring it on every @Transactional annotation. Something like using @ApplicationException(rollback=true) annotation on an exception class in EJB.

3 Answers

This config solves it:

@Configuration
public class MyProxyTransactionManagementConfiguration extends ProxyTransactionManagementConfiguration {

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource() {

            @Nullable
            protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
                TransactionAttribute ta = super.determineTransactionAttribute(element);
                if (ta == null) {
                    return null;
                } else {
                    return new DelegatingTransactionAttribute(ta) {
                        @Override
                        public boolean rollbackOn(Throwable ex) {
                            return super.rollbackOn(ex) || ex instanceof Exception;
                        }
                    };
                }
            }
        };
    }
}

This is a similar approach as this answer, i.e. changing the default globally, but with as minimal change to Spring's config as possible, and still leaving the possibility to customize rollback rules per method as usual (with rollbackFor, noRollbackFor etc.).

This is achieved by simply adding a default RollbackRule for Exception.class. Since the rules have precedence according to the exception class hierarchy (the rule for the most specific exception class applicable wins), the new rule has basically lowest precendence, if no other rules are defined on the annotation.

@Configuration
public class MyTransactionManagementConfiguration {
  /**
   * Note: This custom config does NOT recognize {@code javax.transaction.Transactional} annotations in contrast to
   * the original Spring behaviour. Check the original {@code AnnotationTransactionAttributeSource} source code for an idea how to add that.
   *
   * @see AnnotationTransactionAttributeSource#AnnotationTransactionAttributeSource(boolean)
   */
  @Bean
  @Primary
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionAttributeSource transactionAttributeSourceWithDefaultRollBackForAllExceptions() {
    return new AnnotationTransactionAttributeSource(
        new SpringTransactionAnnotationParser() {
          
          @Override
          protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
            RuleBasedTransactionAttribute rbta = (RuleBasedTransactionAttribute) super.parseTransactionAnnotation(attributes);
            List<RollbackRuleAttribute> rules = new ArrayList<>(rbta.getRollbackRules());
            rules.add(new RollbackRuleAttribute(Exception.class));
            rbta.setRollbackRules(rules);
            return rbta;
          }

        }
    );
  }
}
Related