衆所周之,隔離級別分爲:
Read Uncommited:可以讀取提交的記錄
ReadCommitted:僅讀到提交的數據,會產生幻讀現象
Repeatable Read :對讀取到的數據加鎖,並對讀取的範圍加鎖,不存在幻讀現象
Serializable:讀加讀鎖寫加寫鎖,串行執行
情況一:主鍵(where 主鍵=???)
Read Committed隔離級別
show create table key_id;
+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| key_id | CREATE TABLE `key_id` (
`id` char(128) NOT NULL DEFAULT '',
`data` char(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
mysql> select * from key_id;
+----+------+
| id | data |
+----+------+
| 10 | bb |
| 2 | b |
| 3 | c |
| 4 | a |
| 8 | cd |
+----+------+
第一個事務
start transaction ;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from key_id where id=’3’
-> ;
Query OK, 1 row affected (0.00 sec)
第二個事務
update key_id set data='cc' where id=’3’;
ERROR 1205 (HY000): Lock wait timeoutexceeded; try restarting transaction
update key_id set data='cc' where id=’4’;
Query OK, 1 row affected (0.01 sec)
Id=3的key鎖住了,其他的列可以更新。
#####記錄行鎖
Repeatable Read 隔離級別
事務1
mysql> start transaction ;
Query OK, 0 rows affected (0.00 sec)
mysql> update key_id set data='kl' whereid='8';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
事務2
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update key_id set data='kk' whereid='4';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> delete from key_id where id='4';
Query OK, 1 row affected (0.00 sec)
mysql> delete from key_id where id='8';
^CCtrl-C -- sending "KILL QUERY63" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution wasinterrupted
mysql> insert into no_index values('15','b');
ERROR 1136 (21S01): Column count doesn'tmatch value count at row 1
mysql> insert into key_id values('15','b');
Query OK, 1 row affected (0.00 sec)
#####說明where 主鍵=???或者是Insert時,是行鎖,RepeatableRead和Read Committed沒有區別,並且同一事務內操作不會互鎖。
情況二:沒有索引
CREATE TABLE `no_index` (
`id` int(11) DEFAULT NULL,
`fir` varchar(128) DEFAULT NULL,
`sec` varchar(128) DEFAULT NULL
)
mysql> select * from no_index;
+------+------+------+
| id | fir | sec |
+------+------+------+
| 1 | a | aa |
| 2 | b | bb |
| 3 | c | cc |
+------+------+------+
Read Committed
事務1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from no_index where id=1;
事務2 delete其他行被鎖住
mysql> start transaction;
mysql> delete from no_index where id=3;
Ctrl-C -- sending "KILL QUERY707" to server ...
Ctrl-C -- query aborted.
事務1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from no_index where id=1;
事務2 用update和insert其他行沒有被鎖
mysql> update no_index set id=30 where id=3;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> insert into no_index values('12','a','b');
Query OK, 1 row affected (0.00 sec)
#####在無索引情況下update,insert,delete(Repeatable Read)是全表鎖。然而當其他事務運用到update,insert操作時,會觸發semi-consistent產生優化,全表鎖降爲行鎖,其他事務運用delete操作仍然被全表鎖。
Repeatable Read 隔離級別
事務1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update no_index set id=10where id=1;
事務2用update,insert,delete操作都被鎖住
mysql> insert into no_index values('14','a','b');
Ctrl-C -- sending "KILL QUERY707" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution wasinterrupted
mysql> delete from no_index whereid=3;
Ctrl-C -- sending "KILL QUERY707" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution wasinterrupted
mysql> update no_index set id=30 where id=3;
Ctrl-C -- sending "KILL QUERY707" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution wasinterrupted
######可以看到在無索引情況下Repeatable Read是全表鎖,其他事務運用update,insert操作時不觸及優化。
第三情況:普通索引(where 索引=???)
CREATE TABLE `index_id` (
`id` int(11) DEFAULT NULL,
`fir` varchar(128) DEFAULT NULL,
`sec` varchar(128) DEFAULT NULL,
KEY`id` (`id`)
)
READ-COMMITTED
事務1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from index_id where id=1;
Query OK, 1 row affected (0.00 sec)
事務2
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update index_id set id=1 where id=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#####READ-COMMITTED說明where 索引=???或者是Insert時,是行鎖。
repeatable-read
事務1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from index_id where id=1;
Query OK, 1 row affected (0.01 sec)
事務2 id不能更新爲1,因爲事務1id=1是更新行,id=1有間隙鎖。更新爲其他數字則不受影響
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update index_id set id=10 where id=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update index_id set id=1 where id=3;
Ctrl-C -- sending "KILL QUERY715" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution wasinterrupted
#####可以看到repeatable-read下事務1刪除id這行時,產生行鎖外還產生間隙鎖,使得被更新的這條記錄不會產生幻讀現象。那爲什麼在無索引或者唯一索引時不會有間隙鎖的產生?是因爲唯一索引時保證了被更新的那條記錄只有一條不會產生幻讀。無索引情況下,整個表已經被全部鎖住了,所以不會產生幻讀現象
總結:在Read Committed下,即使不用索引,其他事務使用update,insert其他行不會鎖等待。在repeatable-read下,運用普通索引做DML操作時會增加間隙鎖(爲了保證不會幻讀),即其他數據不能改爲被索引的那個行的那個列的值。如:事務1 update a set id=2 where id=1,事務2 update a set id=1 where id=10; 事務2 間隙鎖造成id改爲1不被允許。