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的方法,不是代理方法,所以不会有事务的存在