关于不同隔离级别下对锁机制的影响
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时,是行锁,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)
事务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这行时,产生行锁外还产生间隙锁,使得被更新的这条记录不会产生幻读现象。那为什么在无索引或者唯一索引时不会有间隙锁的产生?是因为唯一索引时保证了被更新的那条记录只有一条不会产生幻读。无索引情况下,整个表已经被全部锁住了,所以不会产生幻读现象
总结:在[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]
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这行时,产生行锁外还产生间隙锁,使得被更新的这条记录不会产生幻读现象。那为什么在无索引或者唯一索引时不会有间隙锁的产生?是因为唯一索引时保证了被更新的那条记录只有一条不会产生幻读。无索引情况下,整个表已经被全部锁住了,所以不会产生幻读现象
总结:在[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]
相关文章推荐
- MySQL中的integer 数据类型
- MySQL存储过程
- mysql中int、bigint、smallint 和 tinyint的区别与长度
- mysql load data 导出、导入 csv
- source命令执行SQL脚本文件
- MySQL创建用户及权限控制
- MySQL管理数据表
- linux下mysql添加用户
- mysql procedure
- mysql触发器
- MySQL 备份和恢复策略
- mac下安装mysql(转载)
- mysql 修改编码 Linux/Mac/Unix/通用(杜绝修改后无法启动的情况!)
- MySQL数据的导出、导入(mysql内部命令:mysqldump、mysql)
- mysql数据行转列
- Linux下修改MySQL编码的方法
- MySQL Server 日志
- MySQL 安全事宜
- MySQL 备份与恢复