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

READ COMMITTED

(提交读)html

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

    • 既然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. 数据表结构以下:sql

    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隔离级别和锁的关系 是同样的:segmentfault

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