To use Spring declarative transaction we need to use @EnableTransactionManagement on the configuration class and @Transactional annotation on the classes/methods where we want to enable the transaction, but that is not enough to enable Spring's declarative transactions correctly.
Spring's declarative transaction is enabled with AOP proxies so when calling a bean method we have to make sure that the call goes through the proxy. Assuming we are using a Spring managed bean which is not annotated with @Transactional itself, calling its method (say A) which is also not annotated with @Transactional will not be in a transaction. Now if this method calls another method B (in the same bean class) which is annotated with @Transactional , will still not enable transaction in B, that's because bean first call is not made via its transactional AOP proxy.
Example
JavaConfig
@Configuration
@ComponentScan
@EnableTransactionManagement
public class AppConfig {
@Bean
public DataSource h2DataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(h2DataSource());
return transactionManager;
}
}
Example Service bean
In following bean we are going to use TransactionAspectSupport which is a way to know whether transaction within a method is enabled or not.
@Service
public class MyServiceBean {
public void doSomething(){
doSomething3();
}
@Transactional
public void doSomething2(){
doSomething3();
}
@Transactional
public void doSomething3() {
TransactionStatus status=null;
try {
status = TransactionAspectSupport.currentTransactionStatus();
} catch (NoTransactionException e) {
System.err.println(e);
}
System.out.println(status!=null? "active transaction": "no transaction");
}
}
Main class
public class ExampleMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
MyServiceBean bean = context.getBean(MyServiceBean.class);
System.out.println("-- calling doSomething() --");
bean.doSomething();
System.out.println("-- calling doSomething2() --");
bean.doSomething2();
System.out.println("-- calling doSomething3() --");
bean.doSomething3();
}
} -- calling doSomething() -- no transaction -- calling doSomething2() -- active transaction -- calling doSomething3() -- active transaction
Example ProjectDependencies and Technologies Used: - spring-context 5.1.2.RELEASE: Spring Context.
- spring-jdbc 5.1.2.RELEASE: Spring JDBC.
- h2 1.4.197: H2 Database Engine.
- JDK 1.8
- Maven 3.5.4
|