mysql row lock

1. Index invalid row lock becomes table lock



 

2. Gap lock

Some time ago, the system always had an insert deadlock, which was very tangled. After investigation, it was found that it was a gap lock! Gap lock is a kind of row lock in innodb, but this kind of lock locks more than one row of data, it locks multiple rows, which is a data range. The main function of gap lock is to prevent phantom reading, but it will expand the scope of the lock, and sometimes it will bring us trouble, and we have encountered it. In the database parameters, the parameter that controls the gap lock is: innodb_locks_unsafe_for_binlog. The default value of this parameter is OFF, that is, the gap lock is enabled. It is a bool value. When the value is true, it means that the gap lock is disabled. So in order to prevent gap locks, is it necessary to directly set innodb_locaks_unsafe_for_binlog to true? uncertain! Moreover, this parameter will affect master-slave replication and disaster recovery. This method is yet to be discussed.

The emergence of gap locks is mainly concentrated in the case of delete first and then insert in the same transaction. When we delete a record through a parameter, if the parameter exists in the database, then a common row lock is generated at this time, locked The record is then deleted, and the lock is released. If this record does not exist, the problem arises. The database scans the index and finds that the record does not exist. At this time, the delete statement acquires a gap lock, and then the database scans to the left to the first one greater than the given record. For a small value of the parameter, scan to the right to the first value larger than the given parameter, and then use this as a boundary to construct an interval, lock the data in the entire interval, and a gap lock that is particularly prone to deadlock is born. .

For example:
table task_queue
Id taskId
1 2
3 9
10 20
40 41

open a session: session 1

sql> set autocommit=0;

   ##

Cancel autocommit


sql> delete from task_queue where taskId = 20;
sql> insert into task_queue values(20, 20);

when opening a session: session 2

sql> set autocommit=0;

   ##

Cancel autocommit


sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(30, 25);

在没有并发,或是极少并发的情况下, 这样会可能会正常执行,在Mysql中, 事务最终都是穿行执行, 但是在高并发的情况下, 执行的顺序就极有可能发生改变, 变成下面这个样子:
sql> delete from task_queue where taskId = 20;
sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(20, 20);
sql> insert into task_queue values(30, 25);

这个时候最后一条语句:insert into task_queue values(30, 25); 执行时就会爆出死锁错误。因为删除taskId = 20这条记录的时候,20 --  41 都被锁住了, 他们都取得了这一个数据段的共享锁, 所以在获取这个数据段的排它锁时出现死锁。

这种问题的解决办法:前面说了, 通过修改innodb_locaks_unsafe_for_binlog参数来取消间隙锁从而达到避免这种情况的死锁的方式尚待商量, 那就只有修改代码逻辑, 存在才删除,尽量不去删除不存在的记录。

 

间隙锁摘录来源http://blog.csdn.net/andyxm/article/details/44810417

 

 

3.间隙锁再次举例,为的是让大家更清楚了解在什么场景下,会产生间隙锁

 

4.如何锁定一行

select * from table where id = 2 for update;

预定某一行后,其他的操作会被阻塞,直到锁定行的会话提交commit

 

5.查看行锁

show status like 'innodb_row_lock%'

 

行锁各状态说明

Innodb_row_lock_current_waits:当前正在等待锁定的数量;

Innodb_row_lock_time :等待总时长 重要

Innodb_row_lock_time_avg :每次等待所花平均时间; 重要

Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间;

Innodb_row_lock_waits :等待总次数   重要

 

 尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分享系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326403893&siteId=291194637
Recommended