spring-mvc+mybatis注解方式事务管理

配置文件:

<!-- dataSource -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${db.master.url}" />
        <property name="username" value="${db.master.user}" />
        <property name="password" value="${db.master.password}" />
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="mergeStat,wall,log4j2" />
        <property name="initialSize" value="5" />
        <property name="maxActive" value="100" />
        <property name="minIdle" value="10" />
        <property name="maxWait" value="60000" />
        <property name="validationQuery" value="SELECT 'x'" />
        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="1800" />
        <property name="logAbandoned" value="true" />
    </bean>

    <!-- Spring整合Mybatis -->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自动扫描Mapping.xml文件 -->
        <property name="mapperLocations" value="classpath*:/sqlMapperXml/*.xml"></property>
        <property name="configLocation" value="classpath:xml/mybatis-config.xml"></property>
        <property name="typeAliasesPackage" value="com.mingwork.model"/>
        <property name="globalConfig" ref="globalConfig"/>
        <property name="plugins">
            <array>
                <!-- 分页插件配置 -->
                <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor">
                    <property name="dialectType" value="mysql"/>
                    <property name="optimizeType" value="aliDruid" />
                </bean>
            </array>
        </property>
    </bean>

    <!-- MP 全局配置 -->
    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <property name="idType" value="0"/>
        <property name="dbColumnUnderline" value="true"/>
    </bean>

    <!-- MyBatis 动态实现  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 对Dao 接口动态实现,需要知道接口在哪  -->
        <property name="basePackage" value="com.mingwork.mapper"/>
    </bean>
    <!-- 事务管理 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
    <!-- 事务管理 属性 -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="select*" propagation="REQUIRED" read-only="true" />
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <!-- 配置切面 -->
    <aop:config expose-proxy="true" proxy-target-class="true">
        <aop:advisor advice-ref="transactionAdvice" pointcut="execution(* com.mingwork.service..*.*(..))"/>
    </aop:config>

  

上面配置的意思就是配置面向切面,只要servcie中的方法抛出Exception,那么insert,update,delete的sql方法都会回滚。测试时,可以在service方法中故意抛出一个异常,throw new Exception("test"); 那么数据库就不会执行成功。所以在开发时,如果需要对多张表进行操作,而又需要保持事务的一致性的时候,我们就可以把对多张表的操作,写在一个service中的方法中,这样如果有一张表执行失败,抛出异常,其他表的操作也会跟着回滚。

@Transactional参数说明

参数说明
readOnly 是否是只读事务,true表示只读,false表示读写
timeout 事务超时秒数,默认值-1表示永不超时
isolation 隔离级别,例如(isolation = Isolation.READ_UNCOMMITTED)
propagation 事务传播行为,见表propagation说明,例如@Transactional(propagation=Propagation.REQUIRED)
rollbackFor 需要回滚的异常类数组,例如</br>单一异常类:@Transactional(rollbackFor=RuntimeException.class)</br> 多个异常类:@Transactional(rollbackFor={IndexOutOfBoundsException.class, OutOfMemoryException.class})
noRollbackFor 不需要进行回滚的异常类数组,......
rollbackForClassName 需要进行回滚的异常类名称数组,例如</br>单一异常类名称:@Transactional(rollbackForClassName="RuntimeException") </br>多个异常类名称:@Transactional(rollbackForClassName={"IndexOutOfBoundsException","OutOfMemoryException.class"})
noRollbackForClassName 不需要进行回滚的异常类名称数组,......

propagation说明

参数说明
REQUIRED 有事务,加入事务,没有新建一个
NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常
NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
NESTED 如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则执行与REQUIRED类似的操作

 

 

 

 

 

 

Q:我们的工程里,事务的开启跟关闭是由Spring负责的,但具体的SQL语句却是由Mybatis执行的。那么问题来了,Mybatis怎么保证自己执行的SQL语句是处在Spring的事务上下文中?

仔细思考一下这个过程,@Transactional是由spring进行处理的,spring做的事情是从数据源(一般为数据库连接池,比如说druid,c3p0等)获取一个数据库连接,然后在进入方法逻辑前执行setAutoCommit(false)操作,最后在处理成功或者出现异常的时候分别执行commit或者rollback操作。
那么问题来了,开启跟结束事务是由spring获取到数据库连接以后进行操作的,但我们实际执行的update或者insert语句却是由mybatis获取数据库连接进行操作的,可以想到如果想让事务生效,那么spring跟mybatis使用的必须是同一个连接,真实情况是什么样呢?它们之间如何进行无缝衔接?让我们通过源码来分析一下。
具体可以参考下面的链接
https://www.jianshu.com/p/6a880d20a61f

 

posted @ 2018-06-06 14:32  kangjianrong  阅读(2603)  评论(0编辑  收藏  举报