参考:
Spring学习之声明式事务(Spring事务学习这一篇足够了)-CSDN博客
Spring事务-CSDN博客这个好点
事务的概念、ACID特点都和mysql中事务概念一样,不再重复学习mysql学习笔记,语言+函数+多表查询+事务+隔离等级-CSDN博客
编程式事务了解即可
声明式事务
编程式事务需要手动编写代码来管理事务
而声明式事务可以通过配置文件或注解来控制事务。
@Transaction
添加:加到方法/类上代表方法或者类下的所有方法有事务
!注意:当我们在@Transactional注解下的方法中添加try-catch语句来捕获异常时,如果捕获异常后不再抛出RuntimeException及其子类或Error异常,则默认认为该异常已经被处理掉了,不会触发事务的回滚操作。如果我们希望在捕获到异常后继续回滚事务,可以手动抛出RuntimeException或其子类或Error异常或者手动回滚事务:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
自动生成一个事务拦截器(TransactionInterceptor),并将其织入到目标方法所在的代理对象中,从而生成一个带有事务管理功能的代理对象。
事务 失效的八种情况_事务失效-CSDN博客
失效的原因看面试突击85:为什么事务@Transactional会失效? - 知乎,用源码解释的很清楚
(1)上面提到的的try catch把异常处理了。从源码可以看出:当执行的方法中出现了异常,@Transactional 才能感知到,然后再执行事务回滚。
(2)数据库引擎不支持事务,例如MyISAM引擎。
(3)非public修饰的方法。原因是因为 @Transactional 使用的是 Spring AOP 实现的,而 Spring AOP 是通过动态代理实现的,而 @Transactional 在生成代理时会判断,如果方法为非 public 修饰的方法,则不生成代理对象,这样也就没办法自动执行事务了。
(4)time out超时
当在 @Transactional 上,设置了一个较小的超时时间时,如果方法本身的执行时间超过了设置的 timeout 超时时间,那么就会导致本来应该正常删除数据的方法执行失败。
(5)调用类内部@Transactional方法
例如:类内部非直接访问带注解标记的方法 B,而是通过类普通方法 A,然后由 A 调用 B。
因为 @Transactional 是基于 Spring AOP 实现的,而 Spring AOP 又是基于动态代理实现的,而当调用类内部的方法时,不是通过代理对象完成的,而是通过 this 对象实现的,这样就绕过了代理对象,从而事务就失效了。
大白话解读Spring事务传播原理,让你事务管理不再懵逼 - 知乎
事务传播指的是在一个方法调用另一个方法时,事务应该如何进行传播。
Spring事务传播机制根据传播的不同情况,可以分为三类:
支持当前事务:是指当前方法需要在一个事务内执行,如果当前没有事务,则创建一个新的事务。如果当前存在事务,则沿用当前事务。
不支持当前事务:是指当前方法需要在没有事务的情况下执行,如果当前存在事务,则挂起当前事务,执行当前方法,执行完毕后再恢复原先的事务。
嵌套事务:是指在当前事务中开启一个新的事务,这个新的事务可以看做是当前事务的子事务。如果当前没有事务,则创建一个新的事务。
事务的传播方式:
Required(默认):表示当前方法必须在一个事务内执行,如果当前没有事务,则新开启一个事务,如果当前存在事务,则沿用当前事务。它是Spring事务传播机制的默认选项。这种事务传播机制的使用场景是:多个操作需要在同一事务中进行,例如对订单进行下单和扣款操作。
Requires_new:表示当前方法必须在一个新的事务中执行,如果当前存在事务,则挂起当前事务,开启新的事务,执行完毕后再恢复原先的事务。这种事务传播机制的使用场景是:需要将当前事务挂起,执行独立的操作,例如对商品进行库存调整和日志记录。
Nested:表示当前方法必须在一个嵌套事务中执行,如果当前没有事务,则新开启一个事务,如果当前存在事务,则在当前事务的基础上创建一个嵌套事务。这种事务传播机制的使用场景是:需要对当前事务进行子事务的操作,例如对订单进行部分退款操作。