spring 事务注解

94 阅读3分钟

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

配置文件:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273<!-- 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需要回滚的异常类数组,例如
单一异常类:@Transactional(rollbackFor=RuntimeException.class)
多个异常类:@Transactional(rollbackFor={IndexOutOfBoundsException.class, OutOfMemoryException.class})
noRollbackFor不需要进行回滚的异常类数组,......
rollbackForClassName需要进行回滚的异常类名称数组,例如
单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")
多个异常类名称:@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使用的必须是同一个连接,真实情况是什么样呢?它们之间如何进行无缝衔接?让我们通过源码来分析一下。

具体可以参考下面的链接

www.jianshu.com/p/6a880d20a…