目录
线上问题:
事务注意事项
总结:
线上问题:
仔细分析了抛出的异常,发现异常为SocketTimeoutException,查阅事务回滚时需要的异常,发现
默认事务只对error和runtimeException异常会进行回滚,其他异常不会回滚
加上@Transactional(rollbackFor=MyException.class)后事务会捕捉到此类异常,
在Spring里,同样只会rollback unchecked exception(RuntimeExcption及子类),而checked exception(Exception及子类)是不会rollback的,除非你特别声明。
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW,rollbackFor = {MyException1.class,MyException2.class})
因此所有在service层方法中用throws定义的Exception,都必须在事务定义中进行rollback设定。(请勿善忘)
所有在service层方法中被catch处理了的异常,又希望容器辅助rollback的话,必须重抛一个预定义的RuntimeException的子类。(请勿回望)
事务注意事项
要根据实际的需求来决定是否要使用事务,最好是在编码之前就考虑好,不然到以后就难以维护;
如果使用了事务,请务必进行事务测试,因为很多情况下以为事务是生效的,但是实际上可能未生效!
1:事务@Transactional的使用要放再类的公共(public)方法中,需要注意的是在 protected、private 方法上使用 @Transactional 注解,它也不会报错(IDEA会有提示),但事务无效。
2:事务@Transactional是不会对该方法里面的子方法生效!也就是你在公共方法A声明的事务@Transactional,但是在A方法中有个子方法B和C,其中方法B进行了数据操作,但是该异常被B自己处理了,这样的话事务是不会生效的!反之B方法声明的事务@Transactional,但是公共方法A却未声明事务的话,也是不会生效的!如果想事务生效,需要将子方法的事务控制交给调用的方法,在子方法中使用rollbackFor注解指定需要回滚的异常或者将异常抛出交给调用的方法处理。一句话就是在使用事务的时候子方法最好将异常抛出!
3:事务@Transactional由spring控制的时候,它会在抛出异常的时候进行回滚。如果自己使用catch捕获了处理了,是不生效的,如果想生效可以进行手动回滚或者在catch里面将异常抛出,比如throw new RuntimeException();。
总结:
- Spring事务管理是根据异常来进行回滚操作;
- Spring与Mybatis整合时,虽然在Service方法中并没有check异常,但是如果数据库有异常发生,默认会进行事务回滚。
- Spring 如果不添加rollbackFor等属性,Spring碰到Unchecked Exceptions都会回滚,不仅是RuntimeException,也包括Error。
- 如果在事务方法中捕获异常并进行处理,一定要继续抛出异常并在Spring事务管理中进行rollbak-for配置。