资讯专栏INFORMATION COLUMN

mysql死锁解读

mushang / 3189人阅读

摘要:此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。虽然不能完全避免死锁,但可以使死锁的数量减至最少。由于死锁时回滚而由应用程序重新提交。下列方法有助于最大限度地降低死锁按同一顺序访问对象。

死锁(Deadlock)
什么是死锁

所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。

产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

在工作当中可能会遇到数据库CPU等各项指标异常,查看数据库所有进程发现绝大部分查询均处于等待中,那么可以判定应该是遇到了死锁,如下图所示:

SHOW FULL PROCESSLIST;

死锁的影响

当产生某表死锁的一开始,所有涉及这张表的操作都将受到阻塞。假设这张表在业务逻辑上是读写频繁的,那就会使很多操作在那里排队等待,而排队等待会占用数据库连接,当该达到该数据库连接数的最大承载数之后,就会使所有数据库操作均无法再继续下去,致使数据库各项指标异常,导致整个环境崩溃。在生产环境中出现这种问题,那是相当致命的,当发现数据库指标异常时因快速处理!

如何发现死锁

1.查询数据库进程

主要看State字段,如果出现大量 waiting for ..lock 即可判定死锁:

SHOW FULL PROCESSLIST;

注意:需要拥有root组权限(supper),否则只能看到当前用户的进程,无法查询所有

2.查看当前的事务

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

INNODB_TRX 表包含信息关于每个事务(排除只读事务)当前执行的在InnoDB,包含是否事务是等待一个锁, 当事务启动后, SQL语句事务是正在执行

INNODB_TRX Columns 相关列信息:

a) trx_id:innodb存储引擎内部事务唯一的事务id。

b) trx_state:当前事务的状态。

c) trx_started:事务开始的时间。

d) trx_requested_lock_id:等待事务的锁id,如trx_state的状态为LOCK WAIT,那么该值代表当前事务之前占用锁资源的id,如果trx_state不是LOCK WAIT的话,这个值为null。

e) trx_wait_started:事务等待开始的时间。

f) trx_weight:事务的权重,反映了一个事务修改和锁住的行数。在innodb的存储引擎中,当发生死锁需要回滚时,innodb存储引擎会选择该值最小的事务进行回滚。

g) trx_mysql_thread_id:正在运行的mysql中的线程id,show full processlist显示的记录中的thread_id。

h) trx_query:事务运行的sql语句,在实际中发现,有时会显示为null值,当为null的时候,就是t2事务中等待锁超时直接报错(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)后,trx_query就显示为null值

比如事务t2正在运行trx_query: update test.t1 set b="t2" where a=1的sql语句,t1先执行,所以是trx_state: RUNNING先申请的资源一直在运行,而t2后run的所以是trx_state: LOCK WAIT一直在等待t1执行完后释放资源。 但是并不能仔细判断锁的一些详细情况,我们需要再去看当前锁定的事务表数据。

3.查看当前锁定的事务

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

INNODB_LOCKS 表包含信息关于每个锁一个InnoDB 事务已经请求,但是没有获得锁,每个lock一个事务持有是堵塞另外一个事务

INNODB_LOCKS Columns 相关列信息:

a) lock_id:锁的id以及被锁住的空间id编号、页数量、行数量

b) lock_trx_id:锁的事务id。

c) lock_mode:锁的模式。

d) lock_type:锁的类型,表锁还是行锁

e) lock_table:要加锁的表。

f) lock_index:锁的索引。

g) lock_space:innodb存储引擎表空间的id号码

h) lock_page:被锁住的页的数量,如果是表锁,则为null值。

i) lock_rec:被锁住的行的数量,如果表锁,则为null值。

j) lock_data:被锁住的行的主键值,如果表锁,则为null值。

如以下查询 :

mysql> select * from INNODB_LOCKSG

1. row **

lock_id: 3015646:797:3:2

lock_trx_id: 3015646

lock_mode: X

lock_type: RECORD

lock_table: test.t1

lock_index: PRIMARY

lock_space: 797

lock_page: 3

lock_rec: 2

lock_data: 1

2. row **

lock_id: 3015645:797:3:2

lock_trx_id: 3015645

lock_mode: X

lock_type: RECORD

lock_table: test.t1

lock_index: PRIMARY

lock_space: 797

lock_page: 3

lock_rec: 2

lock_data: 1

2 rows in set (0.00 sec)

这里我们可以看到当前的锁信息了,2个事务都锁定了,看相同的数据lock_space: 797、lock_page: 3、lock_rec: 2可以得出事务t1和事务t2访问了相同的innodb数据块,再通过lock_data字段信息lock_data: 1,看到锁定的数据行都是主键为1的数据记录,可见2个事务t1和t2都申请了相同的资源,因此会被锁住,事务在等待。

通过lock_mode: X值也可以看出事务t1和t2申请的都是排它锁。

PS:当执行范围查询更新的时候,这个lock_data的值并非是完全准确。当我们运行一个范围更新时,lock_data只返回最先找到的第一行的主键值id;另外如果当前资源被锁住了,与此同时由于锁住的页因为InnoDB存储引擎缓冲池的容量,而导致替换缓冲池页面,再去查看INNODB_LOCKS表时,这个lock_data会显示未NULL值,意味着InnoDB存储引擎不会从磁盘进行再一次查找。

4.查看当前等锁的事务

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

INNODB_LOCK_WAITS 表包含了blocked的事务的锁等待的状态。当事务量比较少,我们可以直观的查看,当事务量非常大,锁等待也时常发生的情况下,这个时候可以通过INNODB_LOCK_WAITS表来更加直观的反映出当前的锁等待情况:

INNODB_LOCK_WAITSColumns 相关列信息:

a) requesting_trx_id:申请锁资源的事务id。

b) requested_lock_id:申请的锁的id。

c) blocking_trx_id:阻塞的事务id。

d) blocking_lock_id:阻塞的锁的id。

如以下查询:
mysql> select * from INNODB_LOCK_WAITSG

1. row **

requesting_trx_id: 3015646

requested_lock_id: 3015646:797:3:2

blocking_trx_id: 3015645

blocking_lock_id: 3015645:797:3:2

1 row in set (0.00 sec)

mysql>

这里我们可以看到事务t1(3015646)申请了锁资源,而事务t2(3015645)则阻塞了事务t1的申请。

如何处理死锁

杀死进程

通过以上方法一可以查询对应死锁的数据库进程,可以直接杀掉

kill 进程ID

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务回滚,而回滚会取消事务执行的所有工作。由于死锁时回滚而由应用程序重新提交。

下列方法有助于最大限度地降低死锁:

(1)按同一顺序访问对象。
(2)避免事务中的用户交互。
(3)保持事务简短并在一个批处理中。
(4)使用低隔离级别。
(5)使用绑定连接。

by KingFer

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/47931.html

相关文章

  • 一个mysql死锁场景分析

    摘要:最近遇到一个在级别下的死锁问题,感觉有点意思,研究了一下,做个记录。比如等都会给涉及到的行加上行锁,防止其他事务的操作间隙锁在隔离级别下,为了防止幻读现象,除了给记录本身,还需要为记录两边的间隙加上间隙锁。至此,死锁过程分析完毕还没完。。。 最近遇到一个mysql在RR级别下的死锁问题,感觉有点意思,研究了一下,做个记录。涉及知识点:共享锁、排他锁、意向锁、间隙锁、插入意向锁、锁等待队...

    kbyyd24 评论0 收藏0
  • 一个mysql死锁场景分析

    摘要:最近遇到一个在级别下的死锁问题,感觉有点意思,研究了一下,做个记录。比如等都会给涉及到的行加上行锁,防止其他事务的操作间隙锁在隔离级别下,为了防止幻读现象,除了给记录本身,还需要为记录两边的间隙加上间隙锁。至此,死锁过程分析完毕还没完。。。 最近遇到一个mysql在RR级别下的死锁问题,感觉有点意思,研究了一下,做个记录。涉及知识点:共享锁、排他锁、意向锁、间隙锁、插入意向锁、锁等待队...

    VioletJack 评论0 收藏0
  • 一个mysql死锁场景分析

    摘要:最近遇到一个在级别下的死锁问题,感觉有点意思,研究了一下,做个记录。比如等都会给涉及到的行加上行锁,防止其他事务的操作间隙锁在隔离级别下,为了防止幻读现象,除了给记录本身,还需要为记录两边的间隙加上间隙锁。至此,死锁过程分析完毕还没完。。。 最近遇到一个mysql在RR级别下的死锁问题,感觉有点意思,研究了一下,做个记录。涉及知识点:共享锁、排他锁、意向锁、间隙锁、插入意向锁、锁等待队...

    Muninn 评论0 收藏0
  • MySQL数据库规范及解读

    摘要:一基础规范第一条必须使用存储引擎解读支持事务行级锁并发性能更好及内存缓存页优化使得资源利用率更高第二条必须使用字符集解读万国码,无需转码,无乱码风险,节省空间,是的超集,由于近年移动设备的增多,表情以及部分不常见汉字在下会表现为乱码,故需要 一、基础规范 第一条:必须使用InnoDB存储引擎 解读:支持事务、行级锁、并发性能更好、CPU及内存缓存页优化使得资源利用率更高 第二条:必须使...

    Zoom 评论0 收藏0
  • 记一次插入意向锁和Next-Key引起的死锁

    摘要:插入意向锁和其他锁的兼容性锁详解行锁表锁意向锁锁插入意向锁给出了锁介绍及锁兼容情况,及常见的插入意向锁冲突。 说明: (1)为方便测试,以下测试均使用test 测试表,其表结构为: Table: test Create Table: CREATE TABLE `test` ( `id` bigint(20) NOT NULL, `oid` bigin...

    soasme 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<