mysql(InnoDB)事务隔离级别(READ COMMITTED) 与 锁,MVCC

READ COMMITTED

(提交读)

  1. 了解了之前 READ UNCOMMITTED 隔离级别是如何加锁的, 并且在文章中, 已经知道 READ COMMITTED 隔离级别可以解决脏读的问题, 那接下来, 对于 READ COMMITTED 隔离级别, 试想一下如果让你用锁来设计, 你会怎么做?

    • 既然READ COMMITTED 隔离级别可以解决脏读的问题, 也就是他可以让事务只能读其他事务已提交的的记录。
    • 如果用锁机制来实现该隔离级别:
      试想一下, 当在事务A中读取数据D的时候, 假设D之前已经在事务B中了, 并且事务B中对数据D做了修改, 但是事务B还没有完成(commit/rollback), 那如何让事务A无法读取数据D呢?
      当事务B在对数据D操作的时候, 假设给数据D加上了行级的排他锁(X lock), 那事务A自然只能阻塞等事务A完成后才能读取数据D了!
    • 数据库这样做的话确实实现了READ COMMITTED隔离级别的效果, 也就避免了脏读, 但问题是这是一种很低效的做法, 因为对于大部分应用来说, 读操作是多于写操作的, 当写操作加锁时, 那么读操作全部被阻塞, 这样在大用户量高并发的情况下, 会直接降低数据库的读效率。
  2. 那么, 既然用锁机制实现该隔离级别是低效的做法, 数据库是如何做的?
    之前在相关MVCC的文章中可以得到答案: 数据库是使用了 排他锁+MVCC 的机制来实现该隔离级别的, 而不是单纯的使用锁或者单纯的使用MVCC

READ COMMITTED与锁 测试

  1. 数据表结构如下:

    mysql> select * from test_transaction;
    +----+---------------+-----+--------+--------------------+
    | id | user_name     | age | gender | desctiption        |
    +----+---------------+-----+--------+--------------------+
    |  1 | 金刚狼     | 127 |      2 | 我有一双铁爪 |
    |  2 | 钢铁侠-rym | 120 |      1 | 我有一身铁甲 |
    |  3 | 绿巨人     |   0 |      2 | 我有一身肉    |
    +----+---------------+-----+--------+--------------------+
    3 rows in set (0.00 sec)
     
    mysql> 
  2. 重新设置客户端1事务隔离级别为read committed: SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

    mysql> SELECT @@SESSION.tx_isolation;
    +------------------------+
    | @@SESSION.tx_isolation |
    +------------------------+
    | REPEATABLE-READ        |
    +------------------------+
    1 row in set (0.00 sec)
     
    mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> SELECT @@SESSION.tx_isolation;
    +------------------------+
    | @@SESSION.tx_isolation |
    +------------------------+
    | READ-COMMITTED         |
    +------------------------+
    1 row in set (0.00 sec)
     
    mysql> 
  3. 再重新打开一个客户端2并设置事务隔离级别为read committed;
  4. 客户端1中打开事务, 然后更改数据, 先不提交; 然后在客户端2中打开事务, 读取客户端1中尚未提交的那条被修改数据
    clipboard.png
  5. 结果发现在客户端2中可以正常读取到那条数据, 只不过, 那条数据并不是被客户端1事务中修改后的数据, 而是最初的稳定数据, 这就避免了脏读!!
  6. 对于该隔离级别修改数据时使用的锁类型, 其分析方法, 和之前一篇MySQL(INNODB引擎)事务READ UNCOMMITTED隔离级别和锁的关系 是一样的:

    • 可以在客户端1的事务在修改数据并且未提交时, 在客户端2中对同一数据进行修改, 然后在客户端2阻塞阶段通过
      查看表的加锁情况: select * from information_schema.INNODB_LOCKS;,
      事务状态: select * from information_schema.INNODB_TRX;,
      进行分析, 结果就不展示了, 可以自行测试一下, 该隔离级别修改数据时使用的也是排他锁, 并且客户端2的修改语句会锁等待~
      (和之前分析READ UNCOMMITTED隔离级别一样, 既然使用了排他锁, 竟然别的事务还能读取, 这特么不就又违反了排他锁的特性么? 还是那句话, 另一个事务在读取的时候并不会加锁, 而是用的MVCC机制读取的镜像)
  7. 小结:
    InnoDB在该隔离级别(READ COMMITTED)写数据是使用排他锁, 读取数据不加锁而是使用了MVCC机制, 这样就可以大大提高并发读写效率, 写不影响读, 因为读并未加锁, 读的是记录的镜像版本!!

编程空间
欢迎大家交流学习, 有帮助的不要忘记 点赞 和 收藏!

睹物思人~~

795 声望
112 粉丝
0 条评论
推荐阅读
彻底搞清 同步,异步,阻塞,非阻塞的概念性知识
之前反正一直搞不清楚同步和阻塞, 异步和非阻塞的概念, 总感觉同步就是阻塞, 异步就是非阻塞的, 总是搞得晕乎乎的, 于是就重新查了些资料进行了梳理, 如有不对欢迎大家指正;

@13阅读 8.1k评论 7

一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go33阅读 2.5k评论 1

封面图
万字长文~vue+express+mysql带你彻底搞懂项目中的权限控制(附所有源码)
所谓的权限,其实指的就是:用户是否能看到,以及是否允许其对数据进行增删改查的操作,因为现在开发项目的主流方式是前后端分离,所以整个项目的权限是后端权限控制搭配前端权限控制共同实现的

水冗水孚11阅读 1.5k

花了几个月时间把 MySQL 重新巩固了一遍,梳理了一篇几万字 “超硬核” 的保姆式学习教程!(持续更新中~)
MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。

民工哥11阅读 1.1k

封面图
一次偶然机会发现的MySQL“负优化”
今天要讲的这件事和上述的两个sql有关,是数年前遇到的一个关于MySQL查询性能的问题。主要是最近刷到了一些关于MySQL查询性能的文章,大部分文章中讲到的都只是一些常见的索引失效场合,于是我回想起了当初被那个...

骑牛上青山8阅读 2.3k评论 2

Redis的线程模型和事务
我原本只是想学习Redis的事务,但后来发现,Redis和传统关系型数据库的事务在ACID的表现上差异很大。而要想详细了解其中的缘由,就离不开Redis独特的单线程模型,因此本文将二者联系在一起讲解。

KerryWu6阅读 5.9k评论 2

Spring系列-实战篇(5)-数据库的事务和锁
大学里面数据库课考试,事务和锁的相关知识绝对是要划的重点。数据库的事务要遵循ACID(原子性、一致性、隔离性、持久性)四要素,锁又有悲观锁和乐观锁的划分方式。那么今天我们讲讲,如何基于SpringBoot+Mybati...

KerryWu2阅读 5.6k评论 1

睹物思人~~

795 声望
112 粉丝
宣传栏