@EnableTransactionManagement的使用及分析

714 阅读3分钟

使用spring事务的时候有一个总开关@EnableTransactionManagement

1. 事务管理器

Spring Boot 使用事务非常简单

  1. 使用注解 @EnableTransactionManagement 开启事务支持后
  2. 在访问数据库的Service方法上添加注解 @Transactional 便可

关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager 。

  1. 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
  2. 如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。

在这里插入图片描述

2. 确认加载的事务管理器是那个?

@EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication {
 
	@Bean
	public Object testBean(PlatformTransactionManager platformTransactionManager){
		System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
		return new Object();
	}
	 
	public static void main(String[] args) {
		SpringApplication.run(ProfiledemoApplication.class, args);
	}
}

3. 人为的指定使用哪个事务管理器

这些SpringBoot为我们自动做了,这些对我们并不透明,如果你项目做的比较大,添加的持久化依赖比较多,我们还是会选择人为的指定使用哪个事务管理器。
代码如下:

@EnableTransactionManagement
@SpringBootApplication
public class ProfiledemoApplication {
	 
	// 其中 dataSource 框架会自动为我们注入
	@Bean
	public PlatformTransactionManager txManager(DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}
	 
	@Bean
	public Object testBean(PlatformTransactionManager platformTransactionManager) {
		System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
		return new Object();
	}
	 
	public static void main(String[] args) {
		SpringApplication.run(ProfiledemoApplication.class, args);
	}
}
  • 在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
  • 然后在Service中,被 @Transactional 注解的方法,将支持事务。如果注解在类上,则整个类的所有方法都默认支持事务。

4. 多个事务管理器的选择

对于同一个工程中存在多个事务管理器要怎么处理,请看下面的实例,具体说明请看代码中的注释。

@EnableTransactionManagement // 开启注解事务管理,等同于xml配置文件中的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {
	 
	@Resource(name="txManager2")
	private PlatformTransactionManager txManager2;
	 
	// 创建事务管理器1
	@Bean(name = "txManager1")
	public PlatformTransactionManager txManager(DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}
	 
	// 创建事务管理器2
	@Bean(name = "txManager2")
	public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
		return new JpaTransactionManager(factory);
	}
	 
	// 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
	@Override
	public PlatformTransactionManager annotationDrivenTransactionManager() {
		return txManager2;
	}
	 
	public static void main(String[] args) {
		SpringApplication.run(ProfiledemoApplication.class, args);
	}
	 
}

上面定义了两个事务管理器,其中annotationDrivenTransactionManager()方法返回的是默认的事务管理器。 annotationDrivenTransactionManager()这个方法是TransactionManagementConfigurer 接口中定义的方法。源码如下:

public interface TransactionManagementConfigurer {

	/**
	 * Return the default transaction manager bean to use for annotation-driven database
	 * transaction management, i.e. when processing {@code @Transactional} methods.
	 * <p>There are two basic approaches to implementing this method:
	 * <h3>1. Implement the method and annotate it with {@code @Bean}</h3>
	 * In this case, the implementing {@code @Configuration} class implements this method,
	 * marks it with {@code @Bean}, and configures and returns the transaction manager
	 * directly within the method body:
	 * <pre class="code">
	 * &#064;Bean
	 * &#064;Override
	 * public PlatformTransactionManager annotationDrivenTransactionManager() {
	 *     return new DataSourceTransactionManager(dataSource());
	 * }</pre>
	 * <h3>2. Implement the method without {@code @Bean} and delegate to another existing
	 * {@code @Bean} method</h3>
	 * <pre class="code">
	 * &#064;Bean
	 * public PlatformTransactionManager txManager() {
	 *     return new DataSourceTransactionManager(dataSource());
	 * }
	 *
	 * &#064;Override
	 * public PlatformTransactionManager annotationDrivenTransactionManager() {
	 *     return txManager(); // reference the existing {@code @Bean} method above
	 * }</pre>
	 * If taking approach #2, be sure that <em>only one</em> of the methods is marked
	 * with {@code @Bean}!
	 * <p>In either scenario #1 or #2, it is important that the
	 * {@code PlatformTransactionManager} instance is managed as a Spring bean within the
	 * container since most {@code PlatformTransactionManager} implementations take advantage
	 * of Spring lifecycle callbacks such as {@code InitializingBean} and
	 * {@code BeanFactoryAware}. Note that the same guidelines apply to
	 * {@code ReactiveTransactionManager} beans.
	 * @return a {@link org.springframework.transaction.PlatformTransactionManager} or
	 * {@link org.springframework.transaction.ReactiveTransactionManager} implementation
	 */
	TransactionManager annotationDrivenTransactionManager();

}

下面对两个事务管理器进行使用:

@Service
public class DevSendMessageServiceImpl implements SendMessageService {
 
	// 使用value具体指定使用那个指定的事务管理器
	@Transactional(value="txManager1")
	@Override
	public void send() {
		System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
		send2();
	}
	 
	// 在存在多个事务管理器的情况下,如果不使用value具体指定
	// 则默认使用方法 annotationDrivenTransactionManager() 返回的事务管理器,如本例中的txManager2
	@Transactional
	public void send2() {
		System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");	
	}
	 
}

5. 总结

通过上面的例子对事务管理器有了一个清晰的认识,我们知道事务管理器的话:

  1. 使用注解 @EnableTransactionManagement 开启事务支持后
  2. 在访问数据库的Service方法上添加注解 @Transactional 便可
  3. 具体使用哪个事务管理器可以引入starter,或者自己指定。