Spring: automatic rollback on checked exceptions Spring: automatic rollback on checked exceptions spring spring

Spring: automatic rollback on checked exceptions


You can't do it for application level with @Transactional , but you can :

variant 1 : extend @Transactional annotation and put it as default value for rollbackfor. But set rollbackFor unchecked exceptions only that you need .With this you can control rollbacks only for case that you sure , and avoid copy past of @Transactional(rollbackFor =MyCheckedException.class)

Like:

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Transactional(rollbackFor=MyCheckedException.class)public @interface TransactionalWithRollback {}

And use this annotation instead of standard @Transactional.

variant 2 : you can create extension from AnnotationTransactionAttributeSource and override method determineTransactionAttribute:

protected TransactionAttribute  determineTransactionAttribute(AnnotatedElement ae)//Determine the transaction attribute for the given method or class.

TransactionAttribute see TransactionAttribute api , there is a method

boolean rollbackOn(Throwable ex) Should we roll back on the given exception?

protected TransactionAttribute determineTransactionAttribute(    AnnotatedElement ae) {    return new DelegatingTransactionAttribute(target) {        @Override        public boolean rollbackOn(Throwable ex) {           return (check is exception type as you need for rollback );       }};

}

Second approach is not so good as first as you do it really global for transaction manager. Better use custom annotation as you can control it any apply only for methods/classes where you really need it. But if you need it in any case use second variant , it will be your default transnational behavior.


This config solves it:

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

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