MySQL-InnoDB的事务隔离级别

MySQL 是一个服务器/客户端架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话( Session )。我们可以同时在不同的会话里输入各种语句,这些语句可以作为事务的一部分进行处理。不同的会话可以同时发送请求,也就是说服务器可能同时处理多个事务,这样子就会导致不同的事务可能同时访问到相同的记录。
事务有一个特性称之为 隔离性 ,理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大,所以设计数据库提出了各种 隔离级别 ,来最大限度的提升系统并发处理事务的能力。

隔离级别

在这里插入图片描述

MySQL8.0查看事务隔离级别

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.31    |
+-----------+
1 row in set (0.00 sec)

1. READ UNCOMMITTED( RU / 读未提交)

一个事务读到了另一个未提交事务修改过的数据
在这里插入图片描述
Session B 中的事务稍后进行了回滚,Session A 中的事务相当于读到了一个不存在的数据,这种现象就称之为 脏读

2. READ COMMITTED ( RC / 读已提交 )

一个事务读到另一个事务已经提交的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。
在这里插入图片描述
一个事务因读取到另一个事务已提交的 update数据,导致对同一条记录读取两次以上的
结果不一致。这种现象称之为 不可重复读

3. REPEATABLE READ(RR / 可重复读)

一个事务第一次读过某条记录后,即使其他事务修改了该记录的值并且提交,该事务之后再读该条记录时,读到的仍是第一次读到的值,而不是每次都读到不同的数据。
在这里插入图片描述
一个事务因读取到另一个事务已提交的 insert数据。导致对同一张表读取两次以上( 例如between…and 语句 ) 的结果不一致,这种现象称之为 幻读

4. SERIALIZABLE(串行化)

如果我们不允许 读-写 、写-读 的并发操作,可以使用 SERIALIZABLE 隔离级别
在这里插入图片描述

事务和MVCC底层原理

借助MVCC,数据库可以实现READ COMMITTED,REPEATABLE READ隔离级别。
MVCC其核心理念就是数据快照,不同的事务访问不同版本的数据快照,从而实现不同的事务隔离级别。
MySQL-InnoDB引擎依赖 undo日志read view 巧妙地实现了MVCC。
数据库中每条记录后面保存两个隐藏的列,一个保存了行的事务ID,一个保存了行的回滚指针

1. undo日志格式

在这里插入图片描述

  • Type And Flags,对应的日志类型,TRX_UNDO_INSERT_REC ,表示insert操作的undo日志。TRX_UNDO_UPD_EXIST_REC表示update操作的undo日志
  • Undo Number是Undo的一个递增编号。
  • Table ID用来表示是哪张表的修改。
  • Transaction Id,记录了产生这个历史版本事务Id,用作后续MVCC中的版本可见性判断
  • Rollptr,指向的是该记录的上一个版本的位置,沿着Rollptr可以找到一个
    Record的所有历史版本。
  • 下面一组Key Fields的长度不定,因为对应表的主键可能由多个field组成,这里需要记录Record完整的主键信息,回滚的时候可以通过这个信息在索引中定位到对应的Record。
  • 记录的就是当前这个Record版本相对于其之后的一次修改的Delta信息,包括所有被修改的Field的编号,长度和历史值。
  • 在Undo Record的头尾还各留了两个字节用户记录其前序和后继Undo Record的位置。
    在这里插入图片描述
    事务2使用UPDATE语句修改该行数据时,会首先使用排他锁锁定改行,将该行当前的值复制到undo log中,然后再真正地修改当前行的值,最后填写事务ID,使用回滚指针指向undo log中修改前的行。
2. ReadView

ReadView 中主要包含当前系统中还有哪些活跃的读写事务,把它们的事务id放到一个列表中,我们把这个列表命名为为m_ids。
m_up_limit_id:m_ids事务列表中的最小事务id,如果当前列表为空那么就等于m_low_limit_id

m_low_limit_id:系统中将要产生的下一个事务id的值。事务id的上限。

m_creator_trx_id:当前事务id,m_ids中不包含当前事务id。

3. MVCC控制的读操作

① 在执行 SELECT 语句时会先生成一个 ReadView , ReadView 的 m_ids 列表的内容就是当前活跃的事务Id
② 根据m_ids 列表,然后从版本链中挑选可见的记录
③ 如果版本链中版本的 trx_id 属性值小于 m_up_limit_id ,表明生成该版本的事务在生成 ReadView前已经提交,该版本可见。
④ 如果版本链中版本的 trx_id 属性值等于 m_creator_trx_id 既当前事务id,可以被访问。
⑤ 如果版本链中版本的 trx_id 属性值大于等于 m_low_limit_id ,在生成 ReadView 后才生成,所以该版本不可见。
⑥ 如果版本链中版本的 trx_id 属性值在 m_up_limit_id 和 m_low_limit_id 之间,那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中。
如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;
如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。
在这里插入图片描述

4. MVCC小结

在 MySQL 中, READ COMMITTED 和 REPEATABLE READ 隔离级别的的一个非常大的区别就是它们生成ReadView 的时机不同。

使用READ COMMITTED隔离级别的事务在每次查询开始时都会生成一个独立的
ReadView

对于使用 REPEATABLE READ 隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView ,之后的查询不会重复生成

小贴士

  • MVCC 多版本的并发控制,英文全称:Multi Version Concurrency Control
  • 关闭事务自动提交SQL语句:set autocommit=0;
  • 手工提交事务SQL语句: commit;
  • 设置当前事务级别
//查看当前事务级别:
// SELECT @@tx_isolation;
select @@transaction_isolation;
//设置read uncommitted级别:
set session transaction isolation level read uncommitted;
//设置read committed级别:
set session transaction isolation level read committed;
//设置repeatable read级别:
set session transaction isolation level repeatable read;
//设置serializable级别:
set session transaction isolation level serializable;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值