---恢复内容开始---
mysql innodb目前使用范围最广的两种隔离级别为RC和RR,RR修复了RC中所存在的不可重复读
READ COMMITED
不可重复读
在同一事务中两次查看的结果集不同,如下session1的查看结果集受session2提交的事物影响
05:47:35[test](;)> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ session1 03:28:11[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 03:28:21[test](;)> select * from t1; Empty set (0.01 sec) session2 03:28:27[test](;)> insert into t1 values(1,1,1,1,1); Query OK, 1 row affected (0.00 sec) 03:29:25[test](;)> select * from t1; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | +----+------+------+------+------+ 1 row in set (0.00 sec)
幻影读(s)
什么是幻影读
同一事务保证了一致性读后,查询时对提交的事务是不可见的,但是变更的时候是可见的,所以就有可能引发幻影读
为什么会导致幻影读
对于update或delete操作(可以使用 with FOR UPDATE
or LOCK IN SHARE MODE
来进行模拟),innodb只加记录锁(满足条件索引记录)而不是gap锁,gap锁只用于外键约束和duplicate key的检查,所以允许另一事务在锁定的记录旁边自由插入新记录
如col2上有索引,在满足col2>5的条件索引上加索引(对于RC,只在col2为10的索引记录上加X lock),所以在另一会话总插入col2 为非10的记录则会成功
set tx_isolation='read-committed' ; session 1 07:46:16[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 07:46:20[test](;)> select * from t1 where col2>5 for update; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 2 | 2 | 10 | 2 | 2 | +----+------+------+------+------+ 1 row in set (0.00 sec) 07:44:48[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 07:46:36[test](;)> insert into t1 values(3,3,6,3,3); Query OK, 1 row affected (0.00 sec) 07:46:38[test](;)> commit; Query OK, 0 rows affected (0.10 sec) 07:46:31[test](;)> select * from t1 where col2>5; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 3 | 3 | 6 | 3 | 3 | | 2 | 2 | 10 | 2 | 2 | +----+------+------+------+------+ 2 rows in set (0.00 sec)
若col2上无索引,也会是同样的结果现象,如果条件字段上无索引,innodb会先将所有行都加上锁,然后返回给server层根据条件筛选,满足条件则释放行锁,不满足条件则不释放
REPEATABLE READ
如何实现可重复读
事物开始时记录当前的快照版本,事务期间读取的都是事务开始时的快照版本
如何避免幻影读
通过 next-key lock 锁机制,是由index-row lock和gap lock组合成的
如,条件为col2>5,会在区间上[1,5],(5,正无穷)加index-row lock
08:30:02[test](;)> set tx_isolation='repeatable-read' ; 08:30:49[test](;)> select * from t1; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 10 | 2 | 10 | +----+------+------+------+------+ 2 rows in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) 08:31:02[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:31:05[test](;)> select * from t1 where col2>5 for update; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 2 | 2 | 10 | 2 | 10 | +----+------+------+------+------+ 1 row in set (0.00 sec) 08:30:51[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:32:11[test](;)> insert into t1 values(3,3,6,3,6); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
---恢复内容结束---
mysql innodb目前使用范围最广的两种隔离级别为RC和RR,RR修复了RC中所存在的不可重复读
READ COMMITED
不可重复读
在同一事务中两次查看的结果集不同,如下session1的查看结果集受session2提交的事物影响
05:47:35[test](;)> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ session1 03:28:11[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 03:28:21[test](;)> select * from t1; Empty set (0.01 sec) session2 03:28:27[test](;)> insert into t1 values(1,1,1,1,1); Query OK, 1 row affected (0.00 sec) 03:29:25[test](;)> select * from t1; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | +----+------+------+------+------+ 1 row in set (0.00 sec)
幻影读(s)
什么是幻影读
同一事务保证了一致性读后,查询时对提交的事务是不可见的,但是变更的时候是可见的,所以就有可能引发幻影读
为什么会导致幻影读
对于update或delete操作(可以使用 with FOR UPDATE
or LOCK IN SHARE MODE
来进行模拟),innodb只加记录锁(满足条件索引记录)而不是gap锁,gap锁只用于外键约束和duplicate key的检查,所以允许另一事务在锁定的记录旁边自由插入新记录
如col2上有索引,在满足col2>5的条件索引上加索引(对于RC,只在col2为10的索引记录上加X lock),所以在另一会话总插入col2 为非10的记录则会成功
set tx_isolation='read-committed' ; session 1 07:46:16[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 07:46:20[test](;)> select * from t1 where col2>5 for update; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 2 | 2 | 10 | 2 | 2 | +----+------+------+------+------+ 1 row in set (0.00 sec) 07:44:48[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 07:46:36[test](;)> insert into t1 values(3,3,6,3,3); Query OK, 1 row affected (0.00 sec) 07:46:38[test](;)> commit; Query OK, 0 rows affected (0.10 sec) 07:46:31[test](;)> select * from t1 where col2>5; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 3 | 3 | 6 | 3 | 3 | | 2 | 2 | 10 | 2 | 2 | +----+------+------+------+------+ 2 rows in set (0.00 sec)
若col2上无索引,也会是同样的结果现象,如果条件字段上无索引,innodb会先将所有行都加上锁,然后返回给server层根据条件筛选,满足条件则释放行锁,不满足条件则不释放
REPEATABLE READ
如何实现可重复读
事物开始时记录当前的快照版本,事务期间读取的都是事务开始时的快照版本
如何避免幻影读
通过 next-key lock 锁机制,是由index-row lock和gap lock组合成的
如,条件为col2>5,会在区间上[1,5],(5,正无穷)加index-row lock
08:30:02[test](;)> set tx_isolation='repeatable-read' ; 08:30:49[test](;)> select * from t1; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 10 | 2 | 10 | +----+------+------+------+------+ 2 rows in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) 08:31:02[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:31:05[test](;)> select * from t1 where col2>5 for update; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 2 | 2 | 10 | 2 | 10 | +----+------+------+------+------+ 1 row in set (0.00 sec) 08:30:51[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:32:11[test](;)> insert into t1 values(3,3,6,3,6); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction