zoukankan      html  css  js  c++  java
  • 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的方法,不是代理方法,所以不会有事务的存在

     

     

  • 相关阅读:
    11111 Generalized Matrioshkas
    Uva 442 Matrix Chain Multiplication
    Uva 10815 Andy's First Dictionary
    Uva 537 Artificial Intelligence?
    Uva 340 MasterMind Hints
    SCAU 9508 诸葛给我牌(水泥题)
    Uva 10420 List of Conquests(排序水题)
    Uva 409 Excuses, Excuses!
    10/26
    11/2
  • 原文地址:https://www.cnblogs.com/warrior4236/p/13257450.html
Copyright © 2011-2022 走看看