mysql gap lock作用_【MySQL】gap lock 浅析

【MySQL】gap lock 浅析

【定义】

innodb 行级锁 record-level lock大致有三种:record lock, gap lock and Next-KeyLocks。

record lock 锁住某一行记录

gap lock 锁住某一段范围中的记录

next key lock 是前两者效果的叠加。

下面是MYSQL官方文档中相关内容的链接

http://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html

【实验环境】

session 1 20:39:29> show create table gap \G

***************** 1. row *****************

Table: gap

Create Table: CREATE TABLE gap (

id int(11) DEFAULT NULL,

KEY ind_gap_id (id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

insert into gap values(17);

insert into gap values(20);

insert into gap values(33);

insert into gap values(39);

insert into gap values(42);

insert into gap values(43);

session 1 20:39:32> select * from gap;

+——+

| id |

+——+

| 17 |

| 20 |

| 33 |

| 39 |

| 42 |

| 43 |

+——+

6 rows in set (0.00 sec)

【实验】

两个会话都在REPEATABLE-READ 事务隔离级别。且都要在事务中进行。

session 1 20:39:37> start transaction;

Query OK, 0 rows affected (0.00 sec)

session 1 20:39:41> delete from gap where id=33;

Query OK, 1 row affected (0.00 sec)

session 20:40:07>

在会话2中 插入id <20 和 >=39的值 可以执行成功,而当要插入的id [20,39)的值时 会遇到gap lock 。

session 2 20:40:15> start transaction;

Query OK, 0 rows affected (0.00 sec)

session 2 20:40:30> insert into gap values(14);

Query OK, 1 row affected (0.00 sec)

session 2 20:40:59> insert into gap values(18);

Query OK, 1 row affected (0.00 sec)

session 2 20:41:06> insert into gap values(20);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

session 2 20:41:12> insert into gap values(24);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

session 2 20:42:17>

session 2 20:42:53> insert into gap values(35);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

session 2 20:44:09>

session 2 20:44:56> insert into gap values(39);

Query OK, 1 row affected (0.00 sec)

session 2 20:45:13> insert into gap values(40);

Query OK, 1 row affected (0.00 sec)

从上面的实验中可以看出会话1 执行删除语句之后,不仅仅锁住 id=33的记录,同时也锁住区间为[20,39)的记录。具体的原因是执行delete from gap where id=33语句,mysql 会执行索引扫描并在该表上施加一个next-key

lock ,向左扫描到20,向右扫描到39 ,锁定区间左闭右开,所以lock的范围是 [20,39)。

【gap 锁带来的问题】

生产环境中有这样的一个情况:

程序会对一个表message 进行update 和insert

session 1

UPDATE message SET gmt_modified = now(),deal_times = deal_times +1 , status = ‘sending’ , gmt_retry = ‘2012-11-17 23:54:10’

WHERE message_id=18;

insert into message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry)

values (‘hello !’,-1,’sending’,’instance_status_sync’,2,127,now(),now(),now());

session 2

UPDATE message SET gmt_modified = now(),deal_times = deal_times +1 , status = ‘sending’ , gmt_retry = ‘2012-11-17 23:54:10’

WHERE message_id=19;

insert into message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry)

values (‘hello world!’,-2,’sending’,’instance_status_sync’,1,17,now(),now(),now());

对于上述程序在无并发情况下,运行正常,但是并发量大的情况下,执行顺序可能就会变成下面的:

UPDATE message SET gmt_modified = now(),deal_times = deal_times +1 , status = ‘sending’ , gmt_retry = ‘2012-11-17 23:54:10’

WHERE message_id= 61;

UPDATE message SET gmt_modified = now(),deal_times = deal_times +1 , status = ‘sending’ , gmt_retry = ‘2012-11-17 23:54:10’

WHERE message_id= 73;

insert into message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry)

values (‘hello world!’,-2,’sending’,’instance_status_sync’,1,17,now(),now(),now());

insert into message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry)

values (‘hello !’,-1,’sending’,’instance_status_sync’,2,127,now(),now(),now());

此时 往往会报错

[ERROR] Could not execute Write_rows event on table db.message; Deadlock found when trying toget lock; ; try restarting transaction, Error_code: 1213;

前两条update 类型的语句都已经获得了[59,75 )区间内记录的S锁,然后两个事务又分别对该区间段内的message_id=10这个位置请求X锁,这时就发生死锁,谁都请求不到X锁,因为互相都持有S锁。

【解决方案有两种】

1、改变程序中数据库操作的逻辑

2、取消gap lock机制

Gap locking can be disabled explicitly.This occurs if you change the transaction isolation level to READ COMMITTED orenable the innodb_locks_unsafe_for_binlog system variable.

Gap locking 可以被显示的关掉,如果你改变事务隔离级别为READ COMMITTED 或者 启动innodb_locks_unsafe_for_binlog system variable.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值