READ COMMITTED
(提交读)
-
了解了之前
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
隔离级别的效果, 也就避免了脏读
, 但问题是这是一种很低效的做法, 因为对于大部分应用来说, 读操作是多于写操作的, 当写操作加锁时, 那么读操作全部被阻塞, 这样在大用户量高并发的情况下, 会直接降低数据库的读效率。
- 既然
- 那么, 既然用锁机制实现该隔离级别是低效的做法, 数据库是如何做的?
之前在相关MVCC的文章中可以得到答案: 数据库是使用了 排他锁+MVCC 的机制来实现该隔离级别的, 而不是单纯的使用锁或者单纯的使用MVCC
READ COMMITTED与锁 测试
-
数据表结构如下:
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>
-
重新设置
客户端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>
- 再重新打开一个
客户端2
并设置事务隔离级别为read committed; - 在
客户端1
中打开事务, 然后更改数据, 先不提交; 然后在客户端2
中打开事务, 读取客户端1
中尚未提交的那条被修改数据
- 结果发现在
客户端2
中可以正常读取到那条数据, 只不过, 那条数据并不是被客户端1
事务中修改后的数据, 而是最初的稳定数据
, 这就避免了脏读
!! -
对于该隔离级别修改数据时使用的锁类型, 其分析方法, 和之前一篇MySQL(INNODB引擎)事务READ UNCOMMITTED隔离级别和锁的关系 是一样的:
- 可以在
客户端1
的事务在修改数据并且未提交时, 在客户端2
中对同一数据进行修改, 然后在客户端2
阻塞阶段通过查看表的加锁情况: select * from information_schema.INNODB_LOCKS;
,事务状态: select * from information_schema.INNODB_TRX;
,
进行分析, 结果就不展示了, 可以自行测试一下, 该隔离级别修改数据时使用的也是排他锁, 并且客户端2
的修改语句会锁等待~
(和之前分析READ UNCOMMITTED隔离级别一样, 既然使用了排他锁, 竟然别的事务还能读取, 这特么不就又违反了排他锁的特性么? 还是那句话, 另一个事务在读取的时候并不会加锁, 而是用的MVCC机制读取的镜像)
- 可以在
- 小结:
InnoDB在该隔离级别(READ COMMITTED)写数据是使用排他锁, 读取数据不加锁而是使用了MVCC机制, 这样就可以大大提高并发读写效率, 写不影响读, 因为读并未加锁, 读的是记录的镜像版本!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。