事务的四大特性
1. 原子性
2. 一致性
3. 隔离性
4. 持久性
事务的传播行为
在一个事务方法中调用另一个事务的方法才会出现此问题
类型 外部不存在事务 外部存在事务
1. REQUIRED(默认) 开启新的事务 融合到外部事务中
2. SUPPORTS 不开启新的事务 融合到外部事务中
3. REQUIRES_NEW 开启新的事务 不用外部的事务,创建新的事务
4. NOT_SUPPORTED 不开启新的事务 不用外部事务
5. NEVER 不开启新的事务 抛出异常
6. MANDATORY 抛出异常 融合到外部事务中
7. NESTED 开启新的事务 融合到外部事务中,Save机制,外层影响内层,内层不会影响外层
事务失效的情况
(注解)事务的原理是通过AOP来实现的,基于动态代理
代理不生效
spring实现动态代理的方式有两种:
1. 基于接口的jdk动态代理,要求目标代理类需要实现一个接口
2. 基于CGLIB代理
在spring2.0之前,目标如果实现了接口,则使用jdk的动态代理,否则通过cglib实现动态代理
在2.0之后的版本,如果不在配置文件中指定代理方式,默认使用cglib代理(spring.aop.proxy-tartget-class)
将直接标注在接口方法上
@Transactional直接是支持标注在方法和类上面的,标注在接口上,如果对应接口的代理方式是cglib
将通过生成子类的方式生成代理对象,将无法解析到@Transactional注解,从而导致事务的失效
被final 和 static关键字修饰的类或方法
cglib是通过生成目标子类的方式生成代理的,final 和 static修饰后,无法继承父类与父类的方法
类方法内部调用 ```json 事务的管理是通过代理执行的方式生效的,如果是方法的内部调用则不会走代理逻辑,也就调用不到了
解决办法:
1. 新创建一个service,将方法迁移过去.(多多少少有点呆)
2. 在当前类中注入自己,在调用内部方法的时候,通过此对象调用
3. 通过AopContext.currentProxy()获取代理对象
4. 当前类没有被spring管理
```json
当前类没有被spring管理成为ioc容器中的一个bean
框架或底层不支持
- 非public修饰的方法
多线程调用
在底层事务的信息是和线程绑定的
因此在多线程的环境下事务的信息都是独立的,将会导致Spring在接管事务上出现错误
数据库本身不支持事务
-
错误使用!@Transactional
错误的传播机制
PROPAGATION_SUPPORTS,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER。
如果设置了这三种传播机制,在发生异常的时候,事务是不会回滚的
rollbackFor属性设置错误
默认情况下事务进回滚运行时异常和Error,不回滚受检异常(例如IOException)
因此如果方法中抛出IO异常,默认情况下事务也会回滚失败
我们可以通过@Transactional(rollbackFor = Exception.class)的方式进行全异常捕获。
异常被内部catch
如果我们需要对特定的异常进行捕获处理,记得再次将异常抛出,让最外层的事务感知到
嵌套事务
根据不同的场景 选择不同的事务传播行为.