特别说明:事务分为声明式事务、编程式事务 本会最下方会额外介绍两者的区别!
本教程来源于:https://mp.weixin.qq.com/s/MzfOq0VGqtDMaxyvp8SOnA
事务包含的范围越小越好。
1、spring要求被代理方法必须是public
修饰。
spring事务底层使用了aop,也就是通过jdk动态代理或者cglib,帮我们生成了代理类,在代理类中实现的事务功能。 如果方法被static、final修饰了,因为类加载机制就无法通过代理对象帮我们操作了。
2、业务实现多线程处理导致事务失效
首先明确一点,事务是指同一个数据库连接。多线程执行业务,每个线程拿到的数据库连接是不一样的,如果线程A出现了异常,触发回滚,那么线程B是不会触发回滚的!
3、方法内部调用,不是不允许调用,而是事务失效
同一个Service 直接调用自身其他方法
推荐解决方式一:自己注入自己,然后通过IOC的对象指向方法
推荐解决方式二:使用AopContext 代理对象 执行方法
如: ((ServiceA)AopContext.currentProxy()).doSave(user);
此方法原理是:通过Aop获取IOC容器中当前的代理对象去执行。
4、未被spring管理
事务是由SpringIOC管理的。@Controller、@Service、@Component、@Repository等注解,可以自动实现bean实例化和依赖注入的功能。也就是说有这些注解的类,是支持事务的。
如:@Service注解丢失:则意味此对象不被IOC容器锁管理,事务是Spring的,不被管理的对象肯定不会触发事务!
5、数据库引擎不支持事务
MyISAM表不支持事务,目前常用的都是InnerDB 数据库引擎了
6、自己吞了异常
事务只有异常才会回滚,自己catch了异常,则不会回滚
7、异常对象错误
Spring默认只会回滚RuntimeException
(运行时异常),如果自己 throw new Exception(XXXX); 则不回滚,建议:
# catch里执行,触发强制回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
8、自定义了回滚异常
@Transactional(rollbackFor = XXXX.class) 这就声明了此回滚触发必须是XXXX异常
如果正常情况触发的异常不是XXXX,那么久不会被事务所捕捉到,触发回滚!
- 阿里巴巴开发者规范中,还是要求开发者重新指定该参数。因为如果使用默认值,一旦程序抛出了Exception,事务不会回滚,这会出现很大的bug。所以,建议一般情况下,将该参数设置成:Exception或Throwable。 如:@Transactional(rollbackFor = Exception.class)
9、嵌套回滚异常
ServiceA 调用ServiceB的业务,ServiceB调用过程出现了异常,如果ServiceB没有异常处理,那么异常就会抛给ServiceA。如果ServiceA中一个try catch 包含了多个DML语句,那么ServiceA抓到了ServiceB的异常,就会是的ServiceA的所有SQL业务也将会全部回滚!
声明式事务 与 编程式事务对比
声明式事务:
- 一个注解搞定@Transactional
- 开发方便、省事
编程式事务:
- spring还提供了另外一种创建事务的方式 TransactionTemplate
- 事务粒度小
- 避免由于spring aop问题,导致事务失效的问题
编程式事务伪代码
// 注入spring 指定的编程式事务对象
@Autowired
private TransactionTemplate transactionTemplate;
// 编程式事务具体局部代码使用
transactionTemplate.execute((status) => {
// todo 调用service1
addData1();
// todo 调用service2
updateData2();
// todo 如果都没有啥问题,返回true,提交事务,如果返回false,回滚事务
return Boolean.TRUE;
})
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤