hjr-深入说一下事务

事务

事务本质是指一组操作,或者全都成功,或者全都失败

一般我们尽可能让全部成功,所以需要重试,但是如果一直失败我们也需要进行相应处理,因此使用超时检测,当超时后触发回滚

所以事务的三要素是:检测执行,重试 和 回滚

数据库事务

ACID,原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)。

原子性、一致性、持久性,实际上是由InnoDB中的两份日志来保证的,一份是redo log日志,一份是undo log日志。

而隔离性 是通过数据库的锁, 加上MVCC来保证的。

所以数据库事务的本质就是如何实现ACID

所以数据库为了实现事务的ACID,分别使用了,缓存快照,多次提交,redo log,undo do,加锁,MVCC等手段

数据库锁分类

共享锁:加锁后其他线程可以读

排它锁:加锁后其他线程读写都不行

Record Locks(行锁)
行锁,顾名思义,是加在索引行(对!是索引行!不是数据行!)上的锁。比如select * from user where id=1 and id=10,就会在id=1和id=10的索引行上加Record Lock。

Gap Locks(间隙锁)
间隙锁,它会锁住两个索引之间的区域。比如select * from user where id>1 and id<10 for update,就会在id为(1,10)的索引区间上加Gap Lock。

Next-Key Locks(间隙锁)
也叫间隙锁,它是Record Lock + Gap Lock形成的一个闭区间锁。比如select * from user where id>=1 and id<=10,就会在id为[1,10]的索引闭区间上加Next-Key Lock。

这样组合起来就有,行级共享锁,表级共享锁,行级排它锁,表级排它锁。

在数据库增删改查四种操作中,insert、delete和update都是会加排它锁的,而select只有显式声明才会加锁:

mysql InnoDB四种隔离级别

异常情况

脏读:读取了脏数据(不存在的数据)。 事务一读 事务二写(未提交) 事务二读(脏数据) 事务二回滚

不可重复读:既可以读取修改的数据,也可以读取新增的数据(幻读)。 事务一读 事务二写(更新已提交) 事务二读(数据不一致,不可重复读)

幻读:仅可以读取新增的数据,但是无法读取修改的数据; 事务一读 事务二写(新增已提交) 事务二读(数据不一致,幻读)

隔离级别和原理

1、读取未提交(可能发生脏读、不可重复读和幻读现象)

原理:读不会加任何锁。而写会加排他锁,并到事务结束之后释放。

2、读取已提交(可能发生不可重复读和幻读现象)

原理: MVCC多版本并发控制

InnoDB在该隔离级别(READ COMMITTED)写数据时,使用排它锁, 读取数据不加锁而是使用了MVCC机制。

因此,在读已提交的级别下,都会通过MVCC获取当前数据的最新快照,不加任何锁,也无视任何锁(因为历史数据是构造出来的,身上不可能有锁)。

但是,该级别下还是遗留了不可重复读和幻读问题: MVCC版本的生成时机: 是每次select时。这就意味着,如果我们在事务A中执行多次的select,在每次select之间有其他事务更新了我们读取的数据并提交了,那就出现了不可重复读,即:重复读时,会出现数据不一致问题,后面我们会讲解超支现象,就是这种引起的。

3、可重复读(默认)(可能发生幻读现象)

原理:MVCC和 Next-key Lock

针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。

针对当前读(select … for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。

READ COMMITTED级别不同的是MVCC版本的生成时机,即:一次事务中只在第一次select时生成版本,后续的查询都是在这个版本上进行,从而实现了可重复读。

但是因为MVCC的快照只对读操作有效,对写操作无效,举例说明会更清晰一点: 事务A依次执行如下3条sql,事务B在语句1和2之间,插入10条age=20的记录,事务A就幻读了。

4、串行化

原理:该级别下,会自动将所有普通select转化为select … lock in share mode执行,即针对同一数据的所有读写都变成互斥的了,可靠性大大提高,并发性大大降低。

Spring事务

java接触的第一个事务就是Spring事务
1、@Transactional注解
2、注入TransactionTemplate 在业务代码里管理事务

传播行为、隔离级别、事务超时时间、事务是否只读等属性都是可以通过参数配置的

事务本质还是指的数据库操作事务,因此Spring事务本质是封装了各个数据库的事务

比如 Mysql建表时设置的引擎类型设置为 MYISAM的话,即使代码里面添加了@Transactional最终事务也不会生效的。

传播行为

2个事务嵌套的时候如何去处理他们的关系

一句话总结就是,或者合并成一个事务,或者事务各自独立,或者报异常

7 种事务传播行为分别是

1、REQUIRED(Spring默认的事务传播类型 required:需要、依赖、依靠)
作用:

如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务。

举例:

当A调用B的时候:如果A中没有事务,B中有事务,那么B会新建一个事务;如果A中也有事务、B中也有事务,那么B会加入到A中去,变成一个事务,这时,要么都成功,要么都失败。

2、SUPPORTS(supports:支持;拥护)
作用:

当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行。

举例:

如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败),如果A中没有事务,那么B就以非事务方式运行(执行完直接提交)

3、MANDATORY(mandatory:强制性的)
作用:

当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。

举例:

如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败);如果A中没有事务,B中有事务,那么B就直接抛异常了,意思是B必须要支持回滚的事务中运行。

4、REQUIRES_NEW(requires_new:需要新建)
作用:

创建一个新事务,如果存在当前事务,则挂起该事务。B会新建一个事务,A和B事务互不干扰,他们出现问题回滚的时候,也都只回滚自己的事务

5、NOT_SUPPORTED(not supported:不支持)
作用:

以非事务方式执行,如果当前存在事务,则挂起当前事务被调用者B会以非事务方式运行(直接提交),如果当前有事务,也就是A中有事务,A会被挂起(不执行,等待B执行完,返回);A和B出现异常需要回滚,互不影响

6、NEVER(never:从不)
作用:

如果当前没有事务存在,就以非事务方式执行;如果有,就抛出异常。就是B从不以事务方式运行

举例:

A中不能有事务,如果没有,B就以非事务方式执行,如果A存在事务,那么直接抛异常

7、NESTED(nested:嵌套的)
作用:

如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)

隔离级别

5 种事务隔离级别
1 ,默认直接使用数据库的隔离级别

或者自定义 四种和 mysql一样的隔离级别

2、读取未提交
3、读取已提交
4、可重复读
5、串行化

超时时间

控制事务等待还是回滚的判断时间

只读

在多条查询语句一起执行时,其他事务所提交的写操作数据,对该事务都不可见

分布式事务

一个事务中分布式系统之间互相调用,Spring无法控制,需要自己使用第三方工具控制,如Seata,或者自己写代码实现

一个事务中同时操作多个不同的数据库,Spring也无法控制,可以通过分布式事务方案解决

常用的有五种

seata的解决方案前四种

1、2PC到3PC

2PC:事务协调者收集多个参与者节点的Undo和Todo是否准备好的消息,并不会真正更新数据库,当收到所有节点的Undo和Todo都准备好后统一提交

问题,协调者收集每个参与者节点Undo和Todo后是否准备好的消息,并不知道参与者会不会崩溃,如果这时候崩溃了,那么万一需要回滚,就无法让故障节点执行Undo了

3PC:
第一在阶段(当收到所有节点的Undo和Todo是否准备好的消息)之后,再检测一遍每个节点是否出故障了,没问题再统一提交

第二每个节点都加入了超时机制

问题1、阻塞等待 2、协调者单点故障问题 3、协调者发的提交命令丢失了会导致数据不一致

2、AT 模式

拦截分布式系统的所有对数据库操作的SQL,拼接组合到一起,给本批操作生成before image 和 after image,最后或者都成功或者都失败

问题:如果是共享的数据库,数据被其他人修改了,会产生脏写问题

3、TCC模式
3PC是自动回滚Uodo的,TCC相当于3PC模式里自己写补偿代码,然后控制回滚时候的回调到自己的补偿代码里。

4、SAGA模式
事务链条的模式,只关注自己的事务成功即可,每一步都要写补偿代码,出现故障触发补偿代码,适合长事务与旧有系统无法改造与新业务组合的情况

5、事务消息表
多步操作组合到表的一条记录里,都走完后,该记录状态成功
,检测该表是否存在非状态成功的记录,如果有,则重试,如果重试超过了超时时间,则回调回滚操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

架构师小侯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值