关于不同隔离级别下锁机制的研究

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于不同隔离级别下锁机制的研究相关的知识,希望对你有一定的参考价值。

众所周之,隔离级别分为:

  1.       Read Uncommited:可以读取提交的记录

  2.      ReadCommitted:仅读到提交的数据,会产生幻读现象

  3.     Repeatable Read :对读取到的数据加锁,并对读取的范围加锁,不存在幻读现象

  4.     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=3key锁住了,其他的列可以更新。

#####记录行锁

 

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,是行锁,RepeatableReadRead 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 updateinsert其他行没有被锁

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)

#####在无索引情况下updateinsertdeleteRepeatable 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;

 

事务2updateinsertdelete操作都被锁住

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这行时,产生行锁外还产生间隙锁,使得被更新的这条记录不会产生幻读现象。那为什么在无索引或者唯一索引时不会有间隙锁的产生?是因为唯一索引时保证了被更新的那条记录只有一条不会产生幻读。无索引情况下,整个表已经被全部锁住了,所以不会产生幻读现象


以上是关于关于不同隔离级别下锁机制的研究的主要内容,如果未能解决你的问题,请参考以下文章

RR隔离级别下锁情况(探究gap锁和行锁)

数据库的特性与隔离级别和spring事务的传播机制和隔离级别

事务隔离机制原理深入分析以及MySQL不同隔离级别分场景下实验对比

事务和锁机制是什么关系? 开启事务就自动加锁了吗?

锁定机制(悲观/乐观)如何与数据库事务隔离级别相关?

图解MySQL事务隔离级别