(重点)事务的四大特性、事务的隔离级别、事务不生效的场景(及解决办法)、事务的七种传播属性

一、事务的四大特性:ACID

原子性:强调事务的不可分割

一致性:强调事务的执行前后,数据库完整性保持一致

隔离性:强调事务的并发访问,一个事务的执行不应该受到另一个事务的打扰

持久性:强调事务结束后,数据就永久保存在数据库中

二、事务的隔离级别:四种,读未提交、读已提交、可重复读、串行化

1、读未提交Read Uncommited:事务还没提交的时候,修改的数据就让别的事务给读到了----脏读

这个隔离级别会产生脏读、不可重复读、幻读

2、读已提交Read Commited:事务A查询一个数据值是1,过了段时间,事务B把这个数据修改了还提交了,此时事务A再次查询这个数据值变为2了

这是不可重复读,一个事务内对一个数据两次读,可能会读到不一样的值;是oracle、sqlserver的默认隔离级别;

3、可重复读 Repeatable read:事务A在执行过程中,读某个数据的值,无论读多少次都是1,就算过程中事务B将这个数据的值修改并提交了,事务A读到的还是自己事务开始时这个数据的值。这种隔离级别可以防止脏读、不可重复读,是mysql的默认隔离级别

4、幻读:幻读针对的是插入。

某事务将所有记录行的某字段改为了2,结果此时另外一个事务插入了一条数据,该字段默认值是1,突然发现有条数据的值是1,以为产生幻觉了

解决幻读需要锁表

5、串行化:解决幻读就要使用串行化级别的隔离级别,所有事务串行起来,不允许多个事务并行操作,事务被处理为顺序执行

MYSQL默认隔离级别是可重复读Read Repeatable,就是说每个事务都会开启自己要操作的数据的快照,读的都是快照数据,多次读结果一样;

MYSQL通过MVCC多版本并发控制(multi-version concurrency control)  机制来实现

安全性:read uncommitted < read committed < repeatable read < serializable

效率:read uncommitted > read committed > repeatable read > serializable

 

三、事务不生效的场景

1.private、final、static方法,事务不生效,入口方法必须是public ,spring的AOp特性决定的,spring认为private自己用的方法应该自己控制,不应该用事务切进去

底层源码实现原理是:在使用spring的aop代理时,spring的transactionIntereceptor在执行目标方法前后进行拦截之前,CglibAopProxy的内部类DynamicAdvisedInterceptor的intercept方法或者JdkDynamicAopProxy的invoke方法会间接调用AbstractFallbackTransactionAttributeSource的computeTransactionAttribute方法,判断当前目标方法的修饰符是不是public

 

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、确保你的业务和事务入口在同一个线程里,否则事务也是不生效的

事务失效的解决方法:法1、使用ApplicationContextHolder工具类从上下文中获取当前bean,再调用;

法2、使用上下文工具类获取当前对象的代理类@EnableAspectJAutoProxy(exposeProxy=true)然后获取代理对象,再调用:

类class里面有一个方法a有事务注解,一个方法b没有,b中要调用a而事务不失效,则在b内部用class c=(class)AopContext.currentProxy();c.a();

 

四、事务的七种传播属性:常用的是required、requires_new、nested;     (便于记忆:2snr1m,2死男人1m)

1、propagation.required:若外层有事务,则加入这个事务,否则开启一个新的事务。

当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在运行,那么被调用端将在该事务中运行,否则重新开启一个新的事务。若被调用端发生异常,那么调用端和被调用端事务都将回滚。required的效果为外部事务和内部事务同属于一个事务,任何一个回滚都会引起所有事务回滚。

2、propagation.supports:若外层有事务,则加入这个事务,否则以非事务方式执行

3、propagation.mandatory:若外层有事务,则加入这个事务,否则抛出异常

4、propagation.requires_new:开启一个独立的新事务执行。requires_new的效果为外部事务和内部事务属于不同事务,内部事务和外部事务都可以单独回滚

5、propagation.not_supported:方法不应该以事务方法执行,若外层有事务,就以非事务方法执行

6、propagation.never:方法不应该以事务方法执行,若外层有事务,就抛出异常

7、propagation.nested:开启一个外层事务的子事务执行。nested的效果为内部事务为外部事务的子事务,内部事务回滚不会引起外部事务回滚,而外部事务回滚会引起内部事务回滚。

posted on   黑子菜园  阅读(2979)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示