mysql 行锁模拟、锁查看及排除

版权声明:本文为博主原创文章,转载请注明出处! https://blog.csdn.net/chuangxin/article/details/86754156

一、mysql 行锁模拟

1、mysql锁简单说明

Mysql InnoDB行锁有2种,2者不能共存:

  • 共享锁Shared(S) lock,用于读取行记录
  • 互斥锁或叫排它锁Exclusive Lock (X),用于更新、删除行记录

2、先模拟一个行锁。

先用mysql命令框,开启一个事务并执行一条更新语句,但是不提交,如下:

mysql> use saas_tst;
mysql> begin;
mysql> update base_goods set sale_price = 46 where sid = 214;

然后用sqlyog客户端,依然执行上述更新语句,如下:

mysql> update base_goods set sale_price = 47 where sid = 214;

更新操作被阻塞,等很久后,会报ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction.

2、再来模拟一个死锁情况

模拟步骤:
1)用户A开启事务,read一行

mysql> begin;
mysql> select * from base_goods where sid = 214 lock in share mode;

说明: lock in share mode是为了加共享锁,其它事务仍然可以读取,如果是for update则变成互斥锁了,其它事务不能读取。

2)换个客户端,用户B更新该记录

mysql> begin;
mysql> update base_goods set sale_price = 42 where sid = 214;

执行结果:

  • 等很久时:会报ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  • 不等立马执行用户A的更新指令:会报ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

3)用户A更新该记录

mysql> update base_goods set sale_price = 43 where sid = 214;

说明: 假设用户B执行更新操作后,仍在阻塞等待时间内(innodb_lock_wait_timeout),用户A立马执行更新操作,这时数据库系统会检测到死锁:

  • 客户B:拿着锁X,请求客户A释放锁S;
  • 客户A:拿着锁S,请求客户B释放锁X;

死锁发生后,系统会通知客户B产生死锁,并释放锁,客户A可以正常执行事务。

二、mysql锁查看的相关指令

1、show processlist

查看数据库哪些线程正在运行,根据processlist其实很难看出哪些线程被死锁,看下图:
在这里插入图片描述
比如线程[2019]就是用户B更新被锁时执行processlist看到的信息,异常的是通常一个简单的updte操作毫秒级就可执行完,而我们发现processlist中看到的线程[2019]sleep和query间差了64,也就是query指令updating状态时间比较长,有经验的可以据此判断出来期间有可能锁表了。
注: processlist在查看jdbc链接是否泄漏(没及时回收、关闭)倒是特别有用,比如eclipse jetty插件启动web项目时,假设有热部署功能的话,一旦修改了静态类,插件会提示你是否终止或继续等操作?一旦执行的是终止操作,项目停止,此时我们发现jdbc链接没有正常被回收,存在链接泄漏问题,至少阿里开源链接池(druid-1.1.5)是这样的。

2、查看正在被锁定的的表

show OPEN TABLES where In_use > 0;

用户B执行更新操作,被阻塞时,查看结果如下:
在这里插入图片描述

3、查看INFORMATION_SCHEMA系统库锁相关数据表

  • INFORMATION_SCHEMA.INNODB_LOCKS
  • INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
  • INFORMATION_SCHEMA.INNODB_TRX;

三、解决mysql锁简单、暴力方法

1、使用INNODB_TRX查看事务锁的情况

select * from INFORMATION_SCHEMA.INNODB_TRX;

假设有锁的话,截图如下:
在这里插入图片描述
注意:trx_mysql_thread_id字段,对应show processlist的线程ID.

2、kill 线程

如上图kill 2026;kill 2027即可。

mysql> kill 2027;
mysql> kill 2026;

猜你喜欢

转载自blog.csdn.net/chuangxin/article/details/86754156