zoukankan      html  css  js  c++  java
  • spring--mybatis事务总结

    spring--事务原理mybatis--MapperScannerConfigurer 和 mybatis--MapperProxy事务,最近想把spring mybatis中的事务和mapper接口的原理分析分析,陆陆续续写了些,这篇做个总结。

    spring+mybatis mapper接口 声明式事务配置

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
          lazy-init="false">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:sqlmapper/*Mapper.xml"/>
        <property name="plugins">
            <list>
                <bean class="***">
                    <property name="dialect">
                        <bean class="***"/>
                    </property>
                </bean>
            </list>
        </property>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="*.*.*" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        </bean>
    
    <bean id="transactionManager"
              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="do*" read-only="false" rollback-for="java.lang.Exception"/>
                <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
            <aop:pointcut id="pc" expression="execution(* springtry.web.service.*.*(..))"/>
            <aop:advisor pointcut-ref="pc" advice-ref="txAdvice"/>
        </aop:config>

    ps:以上在service层注入事务,do开头方法传播机制是required,其它的是supports

    1. org.mybatis.spring.SqlSessionFactoryBean解析mapper xml配置,根据namespace添加class mapper组装Configuration对象,设置它的environment(包含springManagedTransactionFactory),最后getObject()包装出DefaultSqlSessionFactory;

    2. org.mybatis.spring.mapper.MapperScannerConfigurer扫描basePackage下的mapper接口,每个接口封装为MapperFactoryBean(包含封装了DefaultSqlSessionFactory的SqlSessionTemplate),注册给spring容器。

    ps:当调用"mapper接口"时去DefaultSqlSessionFactory-》Configuration获得接口类的代理类

    MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);

    3. 前面两步是系统的前提工作。

    从service层方法开始,首先进入TransactionInerceptor事务拦截器,由 DataSourceTransactionManager 生成一个DataSourceTransactionObject事务对象,封装在DefaultTransactionStatus中,调用doBegin开启这个事务对象,设置这个事务对象 setConnectionHolder(new ConnectionHolder(Connection ex)),把这个ConnectionHolder 以键值对绑定在当前线程上 <this.getDataSource(),txObject.getConnectionHolder()>

    TransactionSynchronizationManager.bindResource(this.getDataSource(), txObject.getConnectionHolder());

    返回这个 DefaultTransactionStatus对象,封装在TransactionAspectSupport.TransactionInfo中,绑定在当前线程上,之后调用实际service方法

    4. service方法中会注入mybatis mapper接口,调用时实际调用

    MapperFactoryBean-》SqlSessionTemplate-》DefaultSqlSessionFactory-》Configuration.getMapper(mapper接口, SqlSessionTemplate);

     返回MapperProxy对mapper接口的代理,接着调用MapperProxy

    5. MapperProxy中,根据调用的Method返回一个MapperMethod对象.execute(SqlSessionTemplate this.sqlSession, args),其中调用sqlSession.insert,           sqlSession.update,sqlSession.delete,sqlSession.selectList,sqlSession.selectMap,sqlSession.selectOne等,

    6. 接下来调用SqlSessionTemplate的方法,实际调用SqlSessionTemplate.sqlSessionProxy(SqlSessionTemplate.SqlSessionInterceptor拦截器拦截的代理),拦截器中使用 SqlSessionUtils 调用

    SqlSessionTemplate.DefaultSqlSessionFactory.openSession-》Configuration-》environment-》springManagedTransactionFactory

    生成一个SpringManagedTransaction事务对象,封装在一个Executor(SimpleExecutor/ReuseExecutor/BatchExecutor)中,封装在DefaultSqlSession中并返回。

    封装在SqlSessionHolder中,并以键值对绑定在当前线程<DefaultSqlSessionFactory,SqlSessionHolder>

    SqlSessionUtils 返回DefaultSqlSession

    7. 调用DefaultSqlSession的(update/select等),其中

    MappedStatement e = this.configuration.getMappedStatement(接口名.方法名 statement);

    this.executor.query/update

    8. 回到第6步生成的Executor,doupdate/doquery时会prepareStatement,其中会getConnection调用SpringManagedTransaction事务对象的getConnection(),

    DataSourceUtils.getConnection(this.dataSource);

    看 mybatis--MapperProxy事务 最后分析的

    ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);

    使用的是第三步当前线程的键值对,也就是service层开启spring事务的connection

    其实,神秘的spring事务本质还是jdbc的connection,跟我们直接使用jdbc是一样的,但是做了增强

  • 相关阅读:
    使用idea进行远程调试
    map根据属性排序、取出map前n个
    编写shell脚本一键启动 重启 停止springboot jar包
    IDEA给类和方法配置注释模板(参数换行显示)
    springboot文件上传报错
    WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南
    WebMvcConfigurerAdapter详解和过时后的替代方案
    springboot上传文件过大,全局异常捕获,客户端没有返回值
    javascript中Math.random()产生随机数总结
    关于微信中的localStorage及使用cookie的解决方案
  • 原文地址:https://www.cnblogs.com/yhzh/p/5589327.html
Copyright © 2011-2022 走看看