Spring 中基于注解的事务控制及原理分析

时间:2022-07-22
本文章向大家介绍Spring 中基于注解的事务控制及原理分析,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、基本使用

除了 Spring context 之外还需要导入以下几个包:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
</dependency>

首先需要一个配置类,然后使用注解@EnableTransactionManagement开启事务控制,同时需要在容器中导入 事务管理器 PlatformTransactionManager

@Configuration
@ComponentScan("top.wsuo.tx")
@EnableTransactionManagement
public class TxConfig {

    /**
     * 配置数据源
     *
     * @return 数据源
     * @throws Exception 异常
     */
    @Bean
    public DataSource dataSource() throws Exception {
        InputStream is = this.getClass().getResourceAsStream("/db.properties");
        Properties properties = new Properties();
        properties.load(is);
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(properties.getProperty("db.user"));
        dataSource.setPassword(properties.getProperty("db.password"));
        dataSource.setJdbcUrl(properties.getProperty("db.url"));
        dataSource.setDriverClass(properties.getProperty("db.driver"));
        return dataSource;
    }

    /**
     * 将 template 放入容器中
     *
     * @return JdbcTemplate
     * @throws Exception 异常
     */
    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception {
        return new JdbcTemplate(dataSource());
    }

    /**
     * 配置事务管理器
     *
     * @return 返回事务管理器
     * @throws Exception 异常
     */
    @Bean
    public PlatformTransactionManager platformTransactionManager() throws Exception {
        return new DataSourceTransactionManager(dataSource());
    }
}

Service 层调用的时候,只要在需要事务控制的方法上面添加一个 @Transactional 注解即可。

@Service
public class UserService {

    private final UserDao userDao;

    public UserService(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }

    // 标注事务: 出现异常会自动回滚
    @Transactional
    public void insertAccount() {
        userDao.insert();
        System.out.println("插入成功!");
    }
}

于是 Spring 即可自动进行事务控制,体现在发生异常会自动回滚操作。

二、原理分析

1、@EnableTransactionManagement

Spring 中大量使用 Enable*** 注解,他们的原理都类似,比如今天我们要分析的这个注解也是如此。

首先点进去该注解:

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

发现它导入了一个 TransactionManagementConfigurationSelector 组件,就是用来导入组件的,他是 ImportSelector 的实现类。

@Override
protected String[] selectImports(AdviceMode adviceMode) {
	switch (adviceMode) {
		case PROXY:
			return new String[] {AutoProxyRegistrar.class.getName(),
					ProxyTransactionManagementConfiguration.class.getName()};
		case ASPECTJ:
			return new String[] {determineTransactionAspectClass()};
		default:
			return null;
	}
}

发现他就是两个判断,看他的模式是 PROXY 还是 ASPECTJ,然后对应两个类或方法。

2、AutoProxyRegistrar

它的作用就是给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件。

他只是利用后置处理器机制,在对象创建以后包装对象为一个代理对象,代理对象里有增强器,然后代理对象利用拦截器链执行方法,这里和 AOP 的原理一致,所以不解释了。

主要就是执行在 AbstractAutoProxyCreator 抽象类中实现的方法。

3、ProxyTransactionManagementConfiguration

@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
	BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
	advisor.setTransactionAttributeSource(transactionAttributeSource());
	advisor.setAdvice(transactionInterceptor());
	if (this.enableTx != null) {
		advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
	}
	return advisor;
}

他会给容器中注册事务增强器,事务增强器要用事务注解的信息 AnnotationTransactionAttributeSource 解析注解。

还会设置一个 TransactionInterceptor 拦截器,它保存了事务的属性信息和事务管理器,同时他是一个 MethodInterceptor

在目标方法执行的时候会执行拦截器链,事务拦截器的功能是先获取事务相关的属性,再获取 PlatformTransactionManager,如果事先没有执行任何 PlatformTransactionManager,会从容器中按照类型获取。

然后执行目标方法,如果有异常,就获取事务管理器,利用事务管理回滚操作,如果正常利用事务管理器提交操作。