参考:http://imysql.cn/2008_07_10_innodb_tx_isolation_and_lock_mode
本文只是对于“SELECT ... LOCK IN SHARE MODE”和“SELECT ... FORUPDATE”事务中的锁和RR隔离级别内的测试,针对于表结构、索引结构以及其他隔离级别情况下的触发锁类型,可以参考网易何登成网盘中“MySQL 加锁处理分析.pdf”这篇文章,很细致。
何登成百度网盘:http://pan.baidu.com/share/home?uk=4265849107&view=share
下面的内容是参考上面链接博文测试的内容,文字略加修改,方便自己查询和阅读。
SELECT ... LOCK IN SHARE MODE sets a shared mode lock on the rows read. A shared mode lock enables other sessions to read the rows but not to modify them. The rows read are the latest available, so if they belong to another transaction that has not yet committed, the read blocks until that transaction ends. 在读取的行上设置一个共享模式的锁。这个共享锁允许其它session读取数据但不允许修改它。 行读取的是最新的数据,如果他被其它事务使用中而没有提交,读取锁将被阻塞直到那个事务结束。 SELECT ... FOR UPDATE sets an exclusive lock on the rows read. An exclusive lock prevents other sessions from accessing the rows for reading or writing. 在读取行上设置一个排他锁。组织其他session读取或者写入行数据
测试一:
Variable_name | Value | ||||
tx_isolation | REPEATABLE-READ | session 1 | session 2 | ||
1 | update未提交 | select | update t1 set b='z' where a=1 |
select * from t1 where a=1 |
session 1 commit之前,普通select返回的结果都是session 1 commit提交前结果 |
2 | update未提交 | select … lock in share mode | update t1 set b='y' where a=1 |
select * from t1 where a=1 lock in share mode |
session 1 commit以后session 2返回结果 |
3 | update未提交 | select … for update | update t1 set b='x' where a=1 |
select * from t1 where a=1 for update |
session 1 commit以后session 2返回结果 |
RR的隔离级别,对于a=1行的update操作会给行加排他锁 1、普通的select只是对于session 1事务提交前的行数据快照查询 2、select … lock in share mode属于共享锁,与session 1的排他锁互斥,需要等待session 1提交或者回滚 3、select … for update属于排他锁,与session 1的排它锁互斥,所以也需要等待需要等待session 1提交或者回滚 |
测试二:
Variable_name | Value | ||||
tx_isolation | REPEATABLE-READ | ||||
session 1 | session 2 | ||||
query | result | query | result | ||
1 | begin | ||||
2 | begin | ||||
3 | select * from t1 where a=1 for update | ||||
4 | update t1 set b='u' where a=1 |
|
session 2查询需要等待session 1事务处理完成或者回滚 | ||
5 | select * from t1 where a=1 for update 或 select * from t1 where a=1 lock in share mode |
无返回,等待 | |||
6 | select * from t1 where a=1 for update 或 select * from t1 where a=1 lock in share mode |
+---+------+ |
无返回,等待 | session 2查询需要等待session 1事务处理完成或者回滚 | |
7 | commit | +---+------+ |
|||
8 | update t1 set b='w' where a=1 | session 1事务处理完成或者回滚后session 2获得查询结果 | |||
9 | select * from t1 where a=1 for update 或 select * from t1 where a=1 lock in share mode |
+---+------+ |
|||
10 | select * from t1 where a=1 for update 或 select * from t1 where a=1 lock in share mode |
无返回,等待 | session 2事务处理完成或者回滚后session 1获得查询结果 | ||
11 | commit | ||||
12 | +---+------+ |
select * from t1 where a=1 for update 或 select * from t1 where a=1 lock in share mode |
+---+------+ |
测试三:
Variable_name | Value | ||||
tx_isolation | REPEATABLE-READ | ||||
session 1 | session 2 | ||||
query | result | query | result | ||
1 | begin | ||||
2 | select * from t1 where a=1 lock in share mode | +---+------+ |
|||
3 | begin | ||||
4 | select * from t1 where a=1 lock in share mode | +---+------+ |
session 2事务虽然只有一个select但是由于update和select两个所持有的共享锁、排他锁互斥,所以session 1的update事务需要等到session 2提交以后完成 | ||
5 | update t1 set b='m' where a=1 | 无返回,等待 | |||
6 | Query OK, 1 row affected (17.49 sec) Rows matched: 1 Changed: 1 Warnings: 0 |
commit | |||
7 | select * from t1 where a=1 lock in share mode | 无返回,等待 | session 1未提交事务,等待 | ||
8 | commit | +---+------+ |
此后又做了几个测试,总结如下:
type | 类型 |
select | 快照 |
select … lock in share mode | 共享锁 |
select … for update | 排它锁 |
DML | 排它锁 |
select | select … lock in share mode | select … for update | DML | |
select | 快照 | 快照 | 快照 | 快照 |
select … lock in share mode | 快照 | 共享实时 | 互斥等待 | 互斥等待 |
select … for update | 快照 | 互斥等待 | 互斥等待 | 互斥等待 |
DML | 快照 | 互斥等待 | 互斥等待 | 互斥等待 |