关于不同隔离级别下锁机制的研究
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于不同隔离级别下锁机制的研究相关的知识,希望对你有一定的参考价值。
众所周之,隔离级别分为:
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这行时,产生行锁外还产生间隙锁,使得被更新的这条记录不会产生幻读现象。那为什么在无索引或者唯一索引时不会有间隙锁的产生?是因为唯一索引时保证了被更新的那条记录只有一条不会产生幻读。无索引情况下,整个表已经被全部锁住了,所以不会产生幻读现象
以上是关于关于不同隔离级别下锁机制的研究的主要内容,如果未能解决你的问题,请参考以下文章
数据库的特性与隔离级别和spring事务的传播机制和隔离级别