前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 中基于注解的事务控制及原理分析

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

作者头像
wsuo
发布2020-07-30 17:10:14
2850
发布2020-07-30 17:10:14
举报
文章被收录于专栏:技术进阶之路技术进阶之路

一、基本使用

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

代码语言:javascript
复制
<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

代码语言:javascript
复制
@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 注解即可。

代码语言:javascript
复制
@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*** 注解,他们的原理都类似,比如今天我们要分析的这个注解也是如此。

首先点进去该注解:

代码语言:javascript
复制
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

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

代码语言:javascript
复制
@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

代码语言:javascript
复制
@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,会从容器中按照类型获取。

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-07-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、基本使用
  • 二、原理分析
    • 1、@EnableTransactionManagement
      • 2、AutoProxyRegistrar
        • 3、ProxyTransactionManagementConfiguration
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档