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
,会从容器中按照类型获取。
然后执行目标方法,如果有异常,就获取事务管理器,利用事务管理回滚操作,如果正常利用事务管理器提交操作。
- ASP.NET Core提供模块化Middleware组件
- CSS预处理器的对比 — sass、less和stylus
- Gensim实现Word2Vec的Skip-Gram模型简介快速上手对语料进行分词使用gensim的word2vec训练模型
- React第三方组件4(状态管理之Reflux的使用②TodoList上)
- 机器学习(六)Sigmoid函数和Softmax函数1 Sigmoid函数2 Softmax函数
- React第三方组件4(状态管理之Reflux的使用①简单使用)
- React第三方组件3(状态管理之Flux的使用⑤异步操作)
- 使用yo-get下载视频网站视频或其
- React多页面应用3(webpack4 多页面实现)
- 洛谷P2345 奶牛集会
- React多页面应用2(webpack4 处理CSS及图片,引入postCSS,及图片处理等)
- React多页面应用1(webpack4 开发环境搭建,包括热更新,api转发等)
- 洛谷P2345 奶牛集会
- P2880 [USACO07JAN]平衡的阵容Balanced Lineup
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- JavaScript闭包实例讲解
- 最全总结!聊聊 Python 操作PDF的几种方法(合并、拆分、水印、加密)
- 作用域和作用域链的简单理解
- 如何在js中创建对象
- 如何理解JavaScript中的this
- 学习Matplotlib看这一份笔记就够了!
- 6个提升效率的pandas小技巧
- 手把手教你用Python+Pyecharts让微博热搜榜动起来
- JS继承
- call,apply,bind 的完全实现和理 解
- js构造函数的理解
- 实战 | PyQt5制作雪球网股票数据爬虫工具
- 别再问我Python怎么操作Word了!
- Vaex :突破pandas,快速分析100GB大数据集
- 【适合收藏】为了多点时间陪女朋友,我向BAT大佬跪求了这15条JS技巧