MySQL之行锁

Posted 王大军

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL之行锁相关的知识,希望对你有一定的参考价值。

前言

  本章介绍行锁的相关知识。行锁偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突的概率低,但并发度高。

准备

  1. 创建表tb_innodb_lock,注意数据库引擎为InnoDB

CREATE TABLE test_innodb_lock (
    a INT (11),
    b VARCHAR (20) 
) ENGINE INNODB DEFAULT charset = utf8;
insert into test_innodb_lock values (1,\'a\');
insert into test_innodb_lock values (2,\'b\');
insert into test_innodb_lock values (3,\'c\');
insert into test_innodb_lock values (4,\'d\');
insert into test_innodb_lock values (5,\'e\');

   2.创建索引。

create index idx_lock_a on test_innodb_lock(a);

create index idx_lock_a on test_innodb_lock(b);

1.行锁定基本演示

1.打开A、B另个会话,并关闭数据库的自动提交。

set autocommit=0;

2.在A会话中做更新操作, B会话中查询

  

  在B会话查询

   

因为设置了不自动提交,所以A修改的数据,在没有提交之前B是看不到的。且是A/B都要提交,B才可看到

3. 在A会话中做更新操作,然后在B会话中也做更新操作。

可以看到,没有提交之前,B的更新操作阻塞。

这时在A会话中commit操作,可看到B会话中发生了更新操作。

2.索引失效导致行锁升级为表锁

1.在A会话中执行如下更新语句。

  • 当 Where 查询条件中的字段没有索引时,更新操作会锁住全表!
  • Where 条件中的查询字段虽然有索引,但是索引失效时(本例子中是字符串没有加单引号),出现自动转换导致索引失效,从而使锁的级别从行锁升级为表锁,

没有索引或者索引失效时,InnoDB 的行锁变表锁

3. 间隙锁的危害

1.间隙锁定义:

  当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,innodb会给符合条件的已有数据记录的索引项加锁,对于键值在条件范围内但不存在的记录,叫作“间隙(GAP)”。

InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。(Next-Key锁)

2.间隙锁危害:

  因为在Query执行过程中通过范围查找的话,会锁定整个范围内的所有索引键值,即使这个索引不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定值范围内的任何数据。在某些场景下这个可能会对性能造成很大的危害。

3. 间隙锁演示

A会话将2到5的行数据,全部锁住,即使没有2这行数据,B也无法进行添加操作。

在范围之外,B即可执行成功。

4. 如何锁定一行

利用for update

①在A会话中执行如下语句。

此时就锁定了a=6这一行。

②在B会话中对该行进行更新操作。

 只有在A会话中进行了commit后,B会话的更新操作才能执行。

5. 行锁分析

1.使用如下命令。

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:系统启动后到现在总共等待锁的次数。

这个五个状态量中,比较重要的是:

Innodb_row_lock_time、Innodb_row_lock_time_avg和Innodb_row_lock_waits。

尤其是等待次数很高,而且每次等待时长不小时,就需要分析优化了。

6.优化建议

①尽可能让所有数据都通过索引来完成,避免无索引行升级为表锁

②合理设计索引,尽量缩小锁的范围。

③尽可能使用较少的检索条件,避免间隙锁。

④尽量控制事务大小,减少锁定资源量和时间长度。

⑤尽可能降低事务隔离级别。

7.页锁

开销和加锁时间介于表锁和行锁之间,会出现死锁,锁定粒度介于表锁和行锁之间,并发度一般(了解即可)

总结

①InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会更高一些(多个锁,一个锁),但是在整体并发处理能力方面要远远优于MyISAM的表级锁定。当系统处于高并发量的时候,InnoDB的整体性能和MyISAM相比就会有比较明显的优势了。

②InnoDB的行锁定同样尤其脆弱的一面(间隙锁危害),当使用不当时可能会让InnoDB的整体性能表现不仅不能比MyISAM高,甚至可能更差。

以上是关于MySQL之行锁的主要内容,如果未能解决你的问题,请参考以下文章

征服Java面试官!mysql排它锁之行锁

Java开发三年月薪才12K,mysql排它锁之行锁

MySQL锁的用法之行级锁

经典Java开发教程!mysql排它锁之行锁,看看这篇文章吧!

InnoDB事务锁之行锁-insert唯一二级索引重复键加锁案例

InnoDB事务锁之行锁-隐式锁转换显示锁举例理解原理