spring源码分析——事务的实现原理
在对数据库进行操作时,有时候会把多个操作放到一个事务里,保证原子性,那么这个事务是怎么实现的呢?
下面我们先通过一个demo看一下事务的使用:
一:事务的使用
数据库jdbc配置:
##数据源配置 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/study jdbc.username=root jdbc.password=root
spring-context.xml配置:
<!--加载properties配置文件-->
<context:property-placeholder location="classpath*:*.properties" />
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClass}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 指定数据源和配置文件路径 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:UserMapper.xml"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hello.mapper"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/>
写一个类,方法上加上@Transactional注解
@Service
public class TestTransactionalService {
@Autowired
private UserMapper userMapper;
@Transactional
public int add(){
User user = new User();
user.setName("Lucy");
user.setAge("30");
int effectCount = userMapper.insert(user);
System.out.println("影响条数: "+effectCount);
int i = 10/0;
return effectCount;
}
}
测试代码:

运行结果: 从结果可以看到影响条数为1,但是数据库没有数据,可以看出事务回滚生效了
二:事务的原理分析
1:注册埋点,注册BeanDefinition对象,实例化BeanPostProcessor对象,并注册到beanPostProcessors中
配置开启事务管理:

通过命名空间找到对象的handler类:

注册自定义标签tx的属性解析器,AnnotationDrivenBeanDefinitionParser







AutoProxyCreator已经以BeanDefinition的形式注册到了BeanDefinitionMaps中。
注册其他类:



2:实例化并注册到beanPostProcessors中
是在refresh方法的registryBeanPostProcessor中实现的,这里不再赘述
3:寻找增强,创建代理






用增强去匹配当前bean信息:






创建代理:

4:拦截方法,对方法进行增强

TestTransactionalService这个对象已经被代理
进入DynamicAdvisedInterceptor类的intercept方法:

只有一个增强:

TransactionInterceptor 的 invoke方法


抛出异常,进入catch代码块:

回滚事务:



DataSourceTransactionManager类的doRollback回滚方法:

可以看出正在执行回滚操作是在DataSourceTransactionManager类中进行的

下面把导致异常的代码去掉,看一下提交的情况:

提交事务:




调到了DataSourceTransactionManager的doCommit事务:

到这里事务管理的分析就结束了,实现原理就是对数据库的操作方法进行增强,如果执行成功就commit,执行失败就rollback。
a: 看一下异常回滚里面小细节:rollbackFor ,什么异常才回滚?

如果@Transactional注解上不配置rollbackFor 默认是RuntimException 或者 Error

如果自定义rollbackFor类型:

b:如果@Transactional注释的方法不是public修饰的,也不会被代理,找不到@Transactional注解的信息


c:如果是内部调用,会不会生效,从其他类调用add方法:

调用add方法,进入intercept


在add方法中调用addData,实际是调用target的方法,不是代理方法,所以不会有事务的存在


浙公网安备 33010602011771号