Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Transactional does not work when @Validated

If I add @Validated annotation to interface/implementation of my service then the service is not transactional anymore. Stacktrace shows there is no TransactionInterceptor but I see only MethodValidationInterceptor. If I remove @Validated then I see TransactionInterceptor and MethodValidationInterceptor disappears of course. Are these aspects mutually exclusive?

@Service
//@Validated <- here is my problem :)
public interface AdminService {
  String test(String key, String result);
}

public class AdminServiceImpl implements AdminService, BeanNameAware, ApplicationContextAware {

  @Override
  @Transactional(transactionManager = "transactionManager")
  public String test(String key, String result) {

    return "hehe";
  }
}

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableTransactionManagement(order = AspectPrecedence.TRANSACTION_MANAGEMENT_ORDER)
public class AppConfiguration {..}

enter image description here

enter image description here

like image 223
Marek Raki Avatar asked Mar 02 '18 16:03

Marek Raki


People also ask

How do you check if @transactional is working?

You can check if transaction is active using TransactionSynchronizationManager. isActualTransactionActive() . But you should call it before a service method executing. TransactionStatus status = TransactionAspectSupport.

Does @transactional work on protected methods?

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.

Can we use @transactional in DAO layer?

You should use @Transactional at service layer, if you want to change the domain model for client B where you have to provide the same data in a different model,you can change the domain model without impacting the DAO layer by providing a different service or by creating a interface and implementing the interface in ...

Can we use @transactional at class level?

The @Transactional annotation on the class level will be applied to every method in the class. However, when a method is annotated with @Transactional (like, updateFoo(Foo foo) ) this will take precedence over the transactional settings defined at the class level.


1 Answers

SOLVED

@Transactional and @Validated do not work together when a service injecting its own proxy by using ApplicationContextAware interface like below:

  private String beanName;

  private AdminService self;

  @Override
  public void setBeanName(String beanName) {
    this.beanName = beanName;
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    self = applicationContext.getBean(beanName, AdminService.class);
  }

During the debugging process I noticed that setApplicationContext() method is called by ApplicationContextAwareProcessor during the post processing phase in which also MethodValidationPostProcessor (@Validated) and AnnotationAwareAspectJAutoProxyCreator (@Transactional and @Aspects) wrap the original beans into proxy instances.

Invocation of getBean() method in the middle of this process causes the bean not to be fully initialized because some of the post processing operations are not applied. In my case TransactionInterceptor was not added.

enter image description here

For injection of the own proxy to services I finally created specialized Ordered BeaNPostProcessor executed with the LOWEST_PRECEDENCE to be sure I operate on a fully initialized bean.

like image 91
Marek Raki Avatar answered Sep 24 '22 12:09

Marek Raki