事务、事务特性、隔离级别、声明式事务、事务失效

事务

相关知识点:MySQLSpringBoot

什麽是事务?

是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体向系统提交,要么都成功,要么都失败。事务是一组不可再分割的操作集合(工作逻辑单元)

事务的四大特性

原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

原子性 Atomicity

  • 最小工作逻辑单元,要么一起成功,要么一起失败。

一致性 Consistency

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

隔离性 Isolation

  • 别人看的时候不能改
  • 别人改的时候不能看
  • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

持久性 Durability

  • 数据库中事务被提交,数据会永久保存
  • 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

事务的隔离级别

读未提交 Read Uncommitted 读取到未提交的数据 脏读

  • 一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据脏读
  • 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

读已提交 READ COMMITTED 只能读取到已经提交的数据 不可重复读

  • 读已提交是大多数主流数据库的默认事务等级,保证了一个事务不会读取到另一个并行事务已修改但未提交的数据,避免了脏读取。
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

可重复读 REPEATABLE_READ : 两次读取的数据不一致 幻读

  • 保证一个事务不会修改另一个事务读取但未提交(回滚)的数据。避免了脏读和不可重复度的情况,但是带来了更大的性能损失。
  • 在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象
  • 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

串行化 Serializable :

  • 最高的隔离级别,在这个隔离级别下,不会产生任何异常。并发的事务,就像事务是在一个个按照顺序执行一样

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

需要特别注意以下几点

  • MySQL默认的事务隔离级别为repeatable-read
  • MySQL 支持 4 种事务隔离级别
  • 事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.
  • Oracle 支持的 2 种事务隔离级别 READ_COMMITED , SERIALIZABLE
  • SQ规范锁规定的标准,不同的数据库具体的实现可能会有些差异
  • MySQL中默认数据隔离级别是 可重复读 时,并不会锁住读取到的行。
  • 事务隔离级别: 未提交读时,写数据只会锁住相应的行。
  • 事务隔离级别为: 可重复读时,写数据会锁住整张表。
  • 事务隔离级别为: 串行化时,读写数据都会锁住整张表。
  • 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed ,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

事务的传播机制

事务传播行为

1.PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
2.PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
3.PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
5.PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。、

代码展示

待补充~

嵌套事务

什么是嵌套事务?

  • 嵌套是子事务套在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。重点就在于那个save point。看几个问题就明了了:

如果子事务回滚,会发生什么?

  • 父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。

如果父事务回滚,会发生什么?

  • 父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。那么:

事务的提交,是什么情况?

  • 是父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?答案是第二种情况,还是那句话,子事务是父事务的一部分,由父事务统一提交。
  • 参考文章:https://blog.csdn.net/liangxw1/article/details/51197560

Spring中的事务

编程式事务

编程式事务是指在代码中手动管理事务的提交和回滚等操作,代码侵入性比较强

声明式事务

声明式事务是基于AOP切面实现的,他将具体的业务与事务进行解耦,代码的侵入性很低,所以在实际开发中是声明式事务用的比较多。声明式事务有两种实现实现方式,一种是基于TX和AOP的xml配置文件方式,第二种就是基于@Transactional注解了。

📋 @Transactional注解可以作用的地方

可以作用在接口类方法

  • 作用于类
  • 当把@Transactional注解放在类上面时,表示该类所有的public方法都配置相同的事务属性信息。
  • 作用于方法
  • 当类配置了@Transactional,方法也配置了@Transactional时,方法的事务会覆盖类的事务配置信息。
  • 作用于接口
  • 不推荐~这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效

声明式事务的注意事项

  • service调用异常上抛到controller。如果式编译时异常不会自动回滚,如果是运行时异常,会回滚
  • 当前类下使⽤⼀个没有事务的⽅法去调⽤⼀个有事务的⽅法,没有事务的存在。如果是在本类中没有事务的⽅法来调⽤标注注解 @Transactional ⽅法,最后的结论是没有事务的

事物失效的场景

数据库引擎不支持事务

  • 在MySQL数据库中有几种引擎(InnoDB,MyISAM,Memory等等),仅仅InnoDB支持事务,如果数据库底层都不支持事务的话,那么再怎么折腾都是白搭.

私有方法不支持事物

  • @Transactional只能加在public方法上,如果需要在private方法中加入事务,可以使用Aspect配transactionManager使用。
  • 为什么不支持?
    入口的方法必须是public,否则事务不起作用(这一点由Spring的AOP特性决定的,理论上而言,不public也能切入,但spring可能是觉得private自己用的方法,应该自己控制,不应该用事务切进去吧)。另外private 方法, final 方法 和 static 方法不能添加事务,加了也不生效
    • 基于接⼝代理(JDK代理)
      • 基于接⼝代理,凡是类的⽅法⾮public修饰,或者⽤了static关键字修饰,那这些⽅法都不能被Spring AOP增强
    • 基于CGLib代理(⼦类代理)
      • 基于⼦类代理,凡是类的⽅法使⽤了private、static、final修饰,那这些⽅法都不能被Spring AOP增强

本类方法调本类另一个方法

  • @Transactional(propagation = Propagation.REQUIRES_NEW)是无效的,在Spring中是使用代理的方式实现事务,发生自身调用的时候,没有经过Spring的代理,自然事务失效.

不支持事物

  • @Transactional(propagation = Propagation.NOT_SUPPORTED)表示如果当前存在事务就挂起,以没有事务的方式运行,主动不支持事务了,那么再怎么操作也是白搭. 此处贴下Spring的传播行为:
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值