写在前面
接上文,本文主要讲述RR锁的概念和场景
正文
innodb默认隔离级别为RR,本服务用的也是RR,所以我们重点来看下RR相关的东西
假如有如下表:
1
2
3
4
5CREATE TABLE `lotest` (
`type` varchar(20) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '1',
KEY `idx_order_id` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
RR解决了脏读和不可重复读、及大部分场景的幻读。解决的方案是什么呢?就是mvcc解决不可重复读问题。mvcc+gap+record+next-key(record+gap)锁解决幻读问题。
mvcc:后面需要细说,它大概的方案如下:每条记录都有隐藏的trxid来标示当前记录版本号,查询时维护一个readview,用来记录全局的事务的前后顺序,再结合当前事务id,然后结合undo(历史版本记录)来判断当前事务需要访问哪些版本的记录。这样就可以使得一个事务内访问的数据都是一个版本的,不会因为其他事务干扰而select数据不同。如下:
步骤 事务1 事务id 结果 事务2 1 select * from lotest where type=20; trxId=1 value =1 2 select * from lotest where type=20; trxId=2 value =1 3 update lotest set value = 2 where type =20; trxId=3 4 select * from lotest where type=20; trxId=3 value=2 5 select * from lotest where type=20; trxId=1 value =1
record x 锁
比如库中有两条记录:
type name
A20 4
A10 3进行如下步骤
步骤 事务1 结果 事务2 1 update lotest set name = 4 where type =’A20’; success 2 insert into lotest (type) values(‘A20’);/update lotest set name = 4 where type =’A20’; Waiting
然后使用语句查看lock日志,
1
2
3
4
5
6
7
8
9SELECT
FROM
INFORMATION_SCHEMA.INNODB_LOCKS;
SELECT *
FROM
information_schema.innodb_trx
show engine innodb status;结果如下:
gap(间隙锁)举例
比如库中有两条记录:
type name
A20 4
A10 3进行如下操作
步骤 事务1 结果 事务2 1 update lotest set name = 4 where type =’A15’; success 2 insert into lotest (type) values(‘A16’); Waiting 然后使用语句查看lock日志,日志如下:
通过日志可以看到,如果根据索引去更新(delete、update)不存在的数据,那么innodb会定位该不存在的数据相邻的两个索引,并加上X gap锁,X gap锁不互斥,其他事务也可以申请x gap锁,如
步骤 事务1 事务2 1 update lotest set name = 4 where type =’A15’; success 2 update lotest set name = 4 where type =’A16’; success 但是其他事务却不能申请权限大于x gap锁,如插入意向锁和x锁,就如上面截图所示的结果,一致等待最初的事务commit。
Next-key锁
他是record x 锁和gap x锁的集合。如下
步骤 事务1 事务2 结果 1 update lotest set name = 4 where type <=’A20’; success 2 insert into lotest (type) values(‘A16’); Gap x 3 update lotest set name = 4 where type =’A20’; Record x
逻辑和前面两种锁一样,这里就不细说了,也不截图了。
未完待续……