您的位置:首页 > 数据库 > MySQL

关于不同隔离级别下对锁机制的影响

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

总结:在[b]Read Committed下,即使不用索引,其他事务使用update,insert其他行不会锁等待。在[b]repeatable-read下,运用普通索引做DML操作时会增加间隙锁(为了保证不会幻读),即其他数据不能改为被索引的那个行的那个列的值。如:事务1 update a set id=2 where id=1,事务2 [b]update a set id=1 where id=10; 事务2 间隙锁造成id改为1不被允许。[/b][/b][/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息