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

 

 

 

 

 

posted @ 2020-07-06 20:55  程序员三藏  阅读(628)  评论(1编辑  收藏  举报