Spring: automatic rollback of checked exceptions

One way to configure Spring to fallback to is not RuntimeExceptions

using annotation @Transactional(rollbackFor=...)

for service classes. The problem with this approach is that we need to define (rollbackFor = ...) for almost all service classes that seem to be really redundant.


My question is, is there a way to customize the default behavior for the Spring transaction manager to rollback to non RuntimeException

whenever it does, without declaring it in every annotation @Transactional

. Something like using annotation @ApplicationException(rollback=true)

for the exception class in EJB.

+4


source to share


2 answers


You cannot do this for the application layer with @Transactional, but you can:

Option 1: Expands the @Transactional annotation and sets it as the default for rollbackfor. But set rollback For invisible exceptions, just what you need. With this, you can only manage rollbacks for the case you are sure of and avoid copying past @Transactional (rollbackFor = MyCheckedException.class)

how

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

      

And use this annotation instead of the standard @Transactional.

Option 2: You can create an extension from AnnotationTransactionAttributeSource and override the defineTransactionAttribute method:



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

      

TransactionAttribute see TransactionAttribute api , method exists

boolean rollbackOn (Throwable ex) Should this exception be rolled back?

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

      

}

The second approach is not as good as before you make it truly global to the transaction manager. It is better to use custom annotation, as you can control it, only applicable to methods / classes where you really need it. But if you need it anyway, use the second option, this will be your default transnational behavior.

+5


source


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;
                        }
                    };
                }
            }
        };
    }
}

      

0


source







All Articles