一、事务的隔离级别
1、读未提交Read Uncommited:事务还没提交的时候,修改的数据就让别的事务给读到了----脏读
2、读已提交Read Commited:事务A查询一个数据值是1,过了段时间,事务B把这个数据修改了还提交了,此时事务A再次查询这个数据值变为2了
这是不可重复读,一个事务内对一个数据两次读,可能会读到不一样的值;
3、可重复读Read Repeatable:事务A在执行过程中,读某个数据的值,无论读多少次都是1,就算过程中事务B将这个数据的值修改并提交了,事务A读到的还是自己事务开始时这个数据的值。
4、幻读:幻读针对的是插入。
某事务将所有记录行的某字段改为了2,结果此时另外一个事务插入了一条数据,该字段默认值是1,突然发现有条数据的值是1,以为产生幻觉了
解决幻读需要锁表
5、串行化:解决幻读就要使用串行化级别的隔离级别,所有事务串行起来,不允许多个事务并行操作
MYSQL默认隔离级别是可重复读Read Repeatable,就是说每个事务都会开启自己要操作的数据的快照,读的都是快照数据,多次读结果一样;
MYSQL通过MVCC多版本并发控制(multi-version concurrency control) 机制来实现
二、事务不生效的场景
1.private、final、static方法,事务不生效,入口方法必须是public ,spring的AOp特性决定的,spring认为private自己用的方法应该自己控制,不应该用事务切进去
2、Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚(至于为什么spring要这么设计:因为spring认为Checked的异常属于业务的,coder需要给出解决方案而不应该直接扔该框架)
3.同类调用不生效(service方法中调用本类中的另一个方法,事务没有生效):
在同一个类中一个无事务的方法调用另一个有事务的方法,事务是不会起作用的
4.如果使用的是rollbakfor的默认,已检查的异常(所有派生自Error和RuntimeException的类,都是未检查异常.其余的是已检查异常, 比如nullPointException是未检查的,IllegalAccessException 是已检查的)不回滚, 可设为rollbackFor={Exception.class}
5.最好不要把@trasaction注解到接口上:
在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。
6、确认你的类是否被代理了(因为spring的事务实现原理为AOP,只有通过代理对象调用方法才能被拦截,事务才能生效
7、确保你的业务和事务入口在同一个线程里,否则事务也是不生效的