Spring事务的使用及注意事项
一、注意事项
不要在接口上声明@Transactional,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。
@Transactional 的事务开启 ,或者是基于接口的 或者是基于类的代理被创建。所以在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的 。
用REQUIRES_NEW的时候,发现没有起作用
分析了一下,原因是A方法(有事务)调用B方法(要独立新事务),如果两个方法写在同一个类里,spring的事务会只处理能同一个。解决方案1:需要将两个方法分别写在不同的类里。 解决方案2:方法写在同一个类里,但调用B方法的时候,将service自己注入自己,用这个注入对象来调用B方法。
使用了@Transactional的方法,只能是public,@Transactional注解的方法都是被外部其他类调用才有效,故只能是public。道理和上面的有关联。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但事务无效。
由于使用了多数据源,所以在使用事务时需要指定事务的value,如下:
@Transactional(value = "tradeTransactionManager",propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
tradeTransactionManager就是相应的value值。
DaoSupport | 事务value |
---|---|
goodsDaoSupport | goodsTransactionManager |
tradeDaoSupport | tradeTransactionManager |
memberDaoSupport | memberTransactionManager |
sssDaoSupport | sssTransactionManager |
systemDaoSupport | systemTransactionManager |
7.默认只有RuntimeExcetion会触发回滚,经验证明确实如此,所以rollbackFor可以自行设置如下:rollbackFor = {Exception.class},当然具体业务具体处理,可能有的业务抛出的某些异常并不需要触发回滚,所以此时应该细化处理异常。
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor={/*自定义Exception,可以是多个*/ IOException.class})
上面的这个rollbackFor配置,可以理解为:当配置这个事务的方法内返回了IOException,则会触发回滚操作。
8.多数据源事务场景测试
准备: A类中的a方法使用goodsDaoSupport A类中的b方法使用tradeDaoSupport A类中的c方法使用goodsDaoSupport B类中的a方法使用tradeDaoSupport B类中的b方法使用goodsDaoSupport
以下用A-a,A-b,B-a表示
场景 | 结果 |
---|---|
同一个方法不能使用多数据源,无法指定唯一的事务value | 不能使用 |
A-a调用B-a,B-a发生异常 | 两个方法事务均回滚 |
A-a调用B-a,B-a执行后,A-a发生异常 | A-a事务回滚,B-a事务不回滚 |
A-a调用A-b,A-b执行后,A-a发生异常 | A-a事务回滚,A-b事务不回滚 |
A-a调用A-b,A-b执行时发生异常 | A-a事务回滚,A-b事务不回滚 |
A-a调用A-c,发生异常 | A-a事务回滚,A-c事务回滚 |
A-a调用B-b,发生异常 | A-a事务回滚,B-b事务回滚 |
总结: 1). 主方法在任何情况下事务都会回滚 2). 两个方法只要使用同一个数据源,不管是两个类的两个方法,或者自身类的private方法,均能正常回滚(被调用的方法不声明事务,事务也会自动传播) 3). 如果分别使用两个数据源的方法,在调用时,应将自身的出现的异常情况排查后再调用子方法。
9.MySQL数据库表引擎应为InnoDB,否则不支持事务。