Mysql的事务隔离级别

Mysql的事务隔离级别

1. 什么是事务

事务是一系列操作的集合,这些操作要么全部执行,要么全部不执行,不存在中间态。

举个例子:A要转账给B 100个W 这就相当于一个事务,里面有一系列的操作。

  1. 查询A账户的余额
  2. 将A账户的余额减去100个W
  3. 查询B账户的余额
  4. 将B账户的余额增加100个W

假如在执行完第二步后,系统突然断电,如果没有事务的存在,A减少的100个W,在B账户中却增加,相当于凭空消失了100个W。如果我们在转账前开启一个事物,在转账结束后再提交这个事务,这样即使中间发生错误,在该事务期间作出的所有修改都会回滚到事务开始时的状态

2. 事务的四大特性

事务是由存储引擎实现的,常见的存储引擎中InnoDB支持事务,但是MyIsam不支持事务

接下来介绍事务的四个特性 ACID(Atomicity)(Consistency)(Isolation)(Durability)

  • 原子性(Atomicity) : 正如字面意思,事务是不可再分割的最小集合。事务中的操作,要么全部执行生效,要么全部不执行。也就是说如果事务中出现错误,就会回滚到事务开始时的状态
  • 一致性(Consistency) : 事务操作前后数据是始终保持一致的,假如初始状态A账户余额100W B账户余额50W,A向B转账50个W。如果事务执行正常,A账户就变为50W,B账户变为100W。如果事务执行错误,AB账户余额不变。在这过程中AB账户的总额是不变的
  • 隔离性(Isolation) : 数据库支持多个并发事务同时操作数据库,隔离性就可以防止多个事务并发的对数据进行操作时导致的数据不一致,使每个事务拥有各自独立的数据空间,其他事务无法对当前事务的数据造成干扰。
  • 持久性(Durability) : 事务对数据的操作,一旦提交就是永久的,持久化到磁盘上的。

3.并发事务会造成哪些问题

由于Mysql是允许多个客户端连接的,所以并发事务通常会造成三个问题 脏读(dirty read) 不可重复读(non-repeatable read) 幻读(phantom read)

1. 脏读

一个事务读取到了其他活跃事务(开启但未提交的事务)修改的数据

2.不可重复读

一个事物先后查询同一条记录,但是这两次查询返回的数据不一致

3.幻读

一个事务多次查询符合某个条件的记录数量,每次返回的记录数量不一致

4.事务的隔离级别有哪些

Mysql有四种隔离级别 分别为

  • 读未提交(read uncommitted) 可以读取到其他未提交事务作出的变更。可能会出现脏读,不可重复读,幻读

  • 读已提交(read committed) 可以读取到其他已提交事务作出的变更。可能会出现不可重复读,幻读

  • 可重复读(repeatable read) 整个事务读取到的数据,和事务开启时读取到的数据保持一致。可能出现幻读。这是Mysql默认的事务隔离级别。

  • 串行化(serializable) 对记录加读写锁,先操作该记录的事务会持有该锁,其他想要操作该条记录的事务会被阻塞等到锁被释放才可以对该记录进行操作。所有问题都不会发生

隔离水平: 串行化 > 可重复读 > 读已提交 > 读未提交

虽然串行化解决了所有并发问题,但也牺牲了执行效率

执行效率: 读未提交 > 读已提交 > 可重复读 > 串行化

但是即使InnoDB默认的隔离级别是可重复读,但是可重复读已经极大程度上减少了幻读的可能,在可重复读这一隔离级别下解决方案有两种:

  1. 针对快照读(普通select语句),通过MVCC解决幻读
  2. 针对当前读(select … for update等),通过next-key lock(记录锁+间隙锁) 解决幻读问题

5.四种隔离界别具体的是如何实现的呢?

  • 读未提交

    因为可以读取到未提交事务修改的数据,所以直接读取最新的数据就好了

  • 串行化 通过加读写锁来实现隔离的

  • 读已提交和可重复读 都是通过创建Read View来实现的,只不过这两者创建Read View的时机不同,读已提交是在每个语句执行前创建的。可重复读是在开启事务时创建的,整个事务都用同一个Read View

什么是Read View

Read View 可以理解为一个数据快照,记录了当前时刻数据的状态

ReadView中有四个字段分别是

creator_trx_id: 创建该Read View的事务ID

m_ids: 当前活跃事务(已开启但还未提交的事务)ID的列表

min_trx_id: m_ids中的最小值

max_trx_id: m_ids中的最大值+1

在介绍Read View是如何工作前,我还要补充一个知识,那就是在聚簇索引存储一条记录时,还包括两个隐藏字段

trx_id: 更改该条记录的事务ID

roll_pointer: 回滚指针 每次对该条记录进行修改时,都会将旧版本写入 undolog(重做日志),该指针指向该条记录之前的一个版本

那么Read View到底是怎么使用的呢?

一个事物去访问一条记录时,会读取该记录的隐藏列 trx_id

  • 如果该 trx_id 小于 Read View 中的 min_trx_id,那么就代表这个版本的记录是在创建 Read View 前的已提交事务生成的,对当前事务可见

  • 如果该 trx_id 大于等于 max_trx_id 就代表这个版本的记录是在创建 Read View 后开启的事务生成的,对当前事务不可见

  • 如果该 trx_id 在 min_trx_id 和 max_trx_id 之间 那么就要查找 m_ids,如果该 trx_id 在 m_ids 中,就代表这个版本的记录是被当前活跃的事务生成的,对当前事务不可见。如果不在活跃id列表中,就表示生产该版本记录的事务已经提交,对当前事务可见

这种通过版本链来控制并发事务访问同一条记录的行为,就叫做多版本并发控制MVCC(MultiVersion Concurrency Controll)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值