spring事务学习分享

学习主要来源: 点此进入原博客链接

事务参数

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

事务特性

原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。 事务执行
过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务 是一个不可分割的
整体,就像化学中学过的原子,是物质构成的基本单位。

一致性(Consistency): 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了
钱,B却没收到。

隔离性(Isolation): 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在
从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。 

持久性(Durability): 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

事务的传播方式: @Transactional(propagation = PROPAGATION_REQUIRES_NEW)

1. TransactionDefinition.PROPAGATION_REQUIRED:
"如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。"

2. TransactionDefinition.PROPAGATION_REQUIRES_NEW:
"创建一个新的事务,如果当前存在事务,则把当前事务挂起。"

3. TransactionDefinition.PROPAGATION_SUPPORTS:
 "如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。"

4. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
"以非事务方式运行,如果当前存在事务,则把当前事务挂起。"

5. TransactionDefinition.PROPAGATION_NEVER:
"以非事务方式运行,如果当前存在事务,则抛出异常。"

6. TransactionDefinition.PROPAGATION_MANDATORY:
"如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。"

7. TransactionDefinition.PROPAGATION_NESTED:
"如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;"
"如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。"

隔离规则

脏读(Dirty reads)—— 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。

不可重复读(Nonrepeatable read)—— 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数
据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。

幻读(Phantom read)—— 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理
员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生
了幻觉一样,这就叫幻读。

可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

为了避免事务并发状态下脏读、不可重复读、幻读的产生,Spring中定义了五种隔离规则:

1. @Transactional(isolation = Isolation.DEFAULT)
 "使用后端数据库默认的隔离级别 对于MYSQL来说就是可重复读"

2. @Transactional(isolation = Isolation.READ_UNCOMMITTED)
 "是最低的隔离级别,允许读取尚未提交的数据变更(会出现脏读,不可重复读),基本不使用"

3. @Transactional(isolation = Isolation.READ_COMMITTED)
 "允许读取并发事务已经提交的数据(会出现不可重复读和幻读)"

4. @Transactional(isolation = Isolation.REPEATABLE_READ)
"事物开启后,对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改(会出现幻读)"

5. @Transactional(isolation = Isolation.SERIALIZABLE)
"最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务
相关的数据库表来实现的"

事务回滚

 Spring使用声明式事务处理,默认情况下,如果被注解的数据库操作方法中发生了unchecked异常,
 所有的数据库操作将rollback;如果发生的异常是checked异常,默认情况下数据库操作还是会提交的。

checked异常(不会回滚):
表示无效,不是程序中可以预测的。比如无效的用户输入,文件不存在,网络或者数据库链接错误。这些都是
外在的原因,都不是程序内部可以控制的。必须在代码中显式地处理。比如try-catch块处理,或者给所在的方法
加上throws说明,将异常抛到调用栈的上一层。
继承自java.lang.Exception(java.lang.RuntimeException除外)。

unchecked异常(会回滚):
表示错误,程序的逻辑错误。是RuntimeException的子类,比如IllegalArgumentException,
 NullPointerException和IllegalStateException。不需要在代码中显式地捕获unchecked异常做处理。
 继承自 java.lang.RuntimeException
 (而java.lang.RuntimeException继承自java.lang.Exception)。

@Transactional默认只能回滚RuntimeException和RuntimeException下面的子类抛出的异常,
不能回滚 Exception异常;如果需要支持回滚Exception异常,需要显示的指明,
如@Transactional(rollbackFor = Exception.class);

@Transactional注解可以作用于哪些地方?

@Transactional可以作用在接口、类、类方法;

1、作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息,
会导致事务控制的粒度太大,注解参数无法根据每个类方法的实际需求设置;因此,一般@Transactional注解
都会直接添加的需要的方法上;

2、作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配
置信息;

3、作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态
代理, 将会导致@Transactional注解失效;

注意:
1、如果同一个类里面两个方法都添加了@Transactional注解,被调用方使用Propagation.REQUIRES_NEW传播方式;调用方则会抛异常。最后调用方和被调用方对数据库的操作都会回滚。
结论:同类调用,不涉及事务传播;
2、调用方不加事务,被调用方加事务,则被调用方抛异常,最后调用方和被调用方对数据库的操作都不会回滚。
结论:同类方法调用不会调用代理对象的方法,@Transactional注解添加和没添加一样。

@Transactional事务不生效原因

1、事务不作用于非public方法;

2、目标方法用final修饰;
     原因:Spring事务基于Spring AOP,通过JDK动态代理或者CGlib代理,在代理类中实现的事务功能;
但如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法;同样,static修饰的方法,
同样无法通过动态代理,变成事务方法;

3、同一个类中的方法直接内部调用 : 一个类里没有标注事务注解的方法A里去调用标注有事务注解的方法B,最后事务不回滚。
  原因:
  方法被事务管理是因为Apring AOP为其生成代理了对象,但是直接this调用同类方法,
  调用的是目标类对象的方法,而非代理类方法,因此,在同类中的方法直接内部调用,会导致事务失效;
  
  在一个Service内部,事务方法调用事务方法,操作异常都会回滚;普通方法调用事务方法,不会开启新的事务,操作异常都不会回滚。
  是因为spring采用动态代理机制来实现事务控制,
  而动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!

4、事务方法所在的类未被Spring管理;
  原因:使用Spring事务的前提是:对象要被Spring IOC容器管理,需要创建bean实例;打了注解,
 但是忘了在当前类加@Service注解,导致事务不生效,也是小白常见的编码错误;

5、多线程调用;
  如果两个方法不在同一个线程中,获取到的数据库连接不一样,从而是两个不同的事务;
  Spring事务源码中Spring的事务是通过数据库连接Connection来实现的;当前线程中保存了一个map,
  key是数据源, value是数据库连接;只有拥有同一个数据库连接才能同时提交和回滚;如果在不同的线程,
  拿到的数据库连接 肯定是不一样的,所以是不同的事务;

6、存储引擎不支持事务;

7、未开启事务;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值