Waiting Auto-INC LOCK导致死锁

今天下午在看死锁相关的文档,到线上查看一生产数据库的时候,正好发现了show engine innodb status有一个死锁的信息:

LATEST DETECTED DEADLOCK
------------------------
120626 20:00:30
*** (1) TRANSACTION:
TRANSACTION 3 3052385643, ACTIVE 0 sec, process no 3898, OS thread id 1356507456 inserting
mysql TABLES IN USE 1, locked 1
LOCK WAIT 16 LOCK struct(s), heap SIZE 3024, undo log entries 56
MySQL thread id 32282264, query id 9170497209 172.24.52.77 product_db UPDATE
INSERT INTO                     occur_dead_lock_table(xx_id1,xx_id2,xx_cloumn1,STATUS,quantity,xxx_id3,price,gmt_create,gmt_modified) VALUES(19273026495,10378,0x313632373230373A36303039323B32303530333A33323637393435,1,1902,723417070,5600,now(),now())
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS SPACE id 879 page no 241 n bits 808 INDEX `ind_occur_dead_lock_table` OF TABLE `product_db/occur_dead_lock_table` trx id 3 3052385643 lock_m
ode X locks gap BEFORE rec INSERT intention waiting
Record LOCK, heap no 291 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 8; hex 800000000000288b; ASC       ( ;; 1: len 8; hex 80000000000c400d; ASC       @ ;;
 
*** (2) TRANSACTION:
TRANSACTION 3 3052385652, ACTIVE 0 sec, process no 3898, OS thread id 1663498560 setting auto-inc LOCK
mysql TABLES IN USE 1, locked 1
15 LOCK struct(s), heap SIZE 3024, undo log entries 43
MySQL thread id 32231290, query id 9170497216 172.24.36.165 product_db UPDATE
INSERT INTO         occur_dead_lock_table(xx_id1,xx_id2,xx_cloumn1,STATUS,quantity,xxx_id3,price,gmt_create,gmt_modified) VALUES(19400057961,10379,0x313632373230373A333233323438333B32303530333A3235303333333336,1,19713,723417070,5600,now(),now())
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS SPACE id 879 page no 241 n bits 808 INDEX `ind_occur_dead_lock_table` OF TABLE `product_db/occur_dead_lock_table` trx id 3 3052385652 lock_m
ode X
Record LOCK, heap no 251 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 8; hex 800000000000288b; ASC       ( ;; 1: len 8; hex 80000000000c4028; ASC       @(;;
......省略部分内容。。。。。
 
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
TABLE LOCK TABLE `product_db/occur_dead_lock_table` trx id 3 3052385652 LOCK mode AUTO-INC waiting
*** WE ROLL BACK TRANSACTION (2)

我们首先来分析一下LATEST DETECTED DEADLOCK的信息中,出现死锁的表为occur_dead_lock_table,数据库版本:

$mysql -V
mysql Ver 14.12 Distrib 5.0.81, for unknown-linux-gnu (x86_64) using EditLine wrapper

表结构:

CREATE TABLE occur_dead_lock_table (
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
xx_id1 BIGINT(20) NOT NULL,
xx_id2 BIGINT(20) NOT NULL,
xx_cloumn1 VARCHAR(512) NOT,
STATUS tinyint(4) NOT NULL ,
quantity INT(11) NOT NULL ,
xxx_id3 BIGINT(20) NOT NULL ,
price BIGINT(20) NOT NULL ,
gmt_create datetime NOT NULL COMMENT '记录创建时间',
gmt_modified datetime NOT NULL COMMENT '记录最后修改时间',
PRIMARY KEY (id),
KEY ind_occur_dead_lock_table (xx_id2)
) ENGINE=InnoDB AUTO_INCREMENT=842353 DEFAULT CHARSET=gbk ;

死锁出现的场景:
(一).通常发出死锁的时候,两个事务通常都会形成一个‘圈’的逻辑,事务1持有事务2所需要的锁,同时事务2又持有事务1所需要的锁,这样就造成了死锁,这是非常常见的一种死锁;

(二).还有一种情况是负责mysql死锁检测的是一个递归函数lock_deadlock_recursive(),当递归的深度depth超过LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK和cost超过LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK两个内部变量的时候,mysql就会抛出死锁信息;

从show innodb status中dead lock的信息来看:

(1).transaction1显示了正在向occur_dead_lock_table中插入一行数据,它正在等待获得表上的索引ind_occur_dead_lock_table的一个x锁(lock_mode X locks gap before rec insert intention waiting);
(2).transaction2的信息包括两部分:已经持有的锁和正在等待的锁;已持有的锁为一个向occur_dead_lock_table表中插入记录的时候,在其索引上获得的X锁;正在等待的锁为在表occur_dead_lock_table上的一个AUTO-INC锁;

上面的一个信息中很重要的一个锁等待为事务2在等待auto-inc锁,下面我们来分析一下在mysql中auto-increment列的实现:

5.0(5.1.22以下)和5.1(5.1.22以上)在自增列上的实现方式:

a.在5.0(5.1.22以下),auto_increment的实现机制为在innodb存储引擎的内存结构中维护一个自增长计数器,该计数器的值由:
Select max(auto_inc_col) from t for update得到,插入操作首先从这个计数器中得到值,然后赋予自增长列(auto_inc locking),可以看到这个锁本质上是一种表锁,那么其缺点就是必须等待前一个插入完成后,这样在大并发下,其插入性能的并发性不然较差;
b.在5.1(5.1.22以上)中增加了另外一种实现机制,在innodb引擎中提供了一种轻量级互斥量(mutex)的自动增长机制,对于普通的insert 操作,innodb用一个mutex去对内存中的计数器进行累加,去掉了对原表的表锁机制,无疑会对部分插入提高较大的性能,该机制在5.1(5.1.22以上)中为自增长值实现的默认方式;

从上面可以看到,在mysql 5.0(5.1.22以下)中自增的id的实现采用的是table lock的方式,这样无疑是加大了死锁出现的概率,该bug已经在5.1.22中修复,新加入了参数就innodb_autoinc_lock_mode(默认为innodb_autoinc_lock_mode = 1 ):

There is a new innodb_autoinc_lock_mode system variable to configure the locking behavior thatInnoDB uses for generating auto-increment values. The default behavior now is slightly different from before,which involves a minor incompatibility for multiple-row inserts that specify anexplicit value for the auto-increment column in some but not all rows.

同时在大并发插入的情况,还会抛出dead lock的(TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH—场景2),该bug已经修复:

“SHOW INNODB STATUS deadlock info incorrect when deadlock detection aborts”. Print the correctlock owner when recursive function lock_deadlock_recursive() exceeds its maximum depth LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK.

综上所述,将版本从5.0升级到5.1的版本(5.1.48或者5.1.61)是不错的选择,同时在业务上可以考虑选择由应用程序产生了一个序列值来插入到数据库中,代替数据库的auto_incement。

时间: 2024-12-31 11:27:51

Waiting Auto-INC LOCK导致死锁的相关文章

MySQL Innodb表导致死锁日志情况分析与归纳_Mysql

案例描述在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志.两个sql语句如下:(1)insert into backup_table select * from source_table(2)DELETE FROM source_table WHERE Id>5 AND titleWeight<32768 AND joinTime<'$daysago_1week'teamUser表的表结构如下:PRIMARY

进程间共享内存 由于某个进程异常退出导致死锁

解决Nginx和Fpm-Php等内部多进程之间共享数据问题 概念说明: 1. MINIT:Php扩展的初始化方法,整个模块启动时候被调用一次 2. RINIT:Php扩展的初始化方法,每个请求会调用一次 3. ClusterMap(简称CM):提供服务定位和集群地图功能,通过接收心跳和主动探测方式收集节点状态信息,统一管理多种异构集群,替换硬负载均衡设备 4. CMSubProxy:ClusterMap内部的一个订阅者客户端代理,定期和Server端通讯,获取最新的集群信息,更新内部维护的机器列

sqlserver2008-各位大神,请问sql的两个事务中的select如何能导致死锁

问题描述 各位大神,请问sql的两个事务中的select如何能导致死锁 捕获的trace日志非常大,我先放下出错的两条语句. sqlserver profiler捕获的是这样一条错误. 我想知道的是明明是两条select,S锁为何会导致死锁.而且死锁图形中的的排它锁是怎么回事,明明对keeping的这个资源没有update,只有delete,delete也会增加排它锁吗?行级的,还是表级的,为何我在prfiler中 捕获update或者delete时mode列没有提示锁? 问的有点多,请先看下图

一段不知道会不会导致死锁的代码

问题描述 问题是这样的,目前有个应用,平时没有问题,但极少数情况下会抛出数据库死锁的异常,我怀疑有可能是并发操作的时候出现,检查之后定位到这一段执行update的语句,请帮忙看看,有没有可能导致死锁调用这个方法的是methodA,methodA中先把Autocommit设为false,然后循环调用executeUpdate(String sql),因为可能会有多条sql需要执行,最后commit,再回复Autocommit为trueexecuteUpdate(String sql)的代码如下pu

ora-00054表被lock导致资源忙等待不能操作的原因及解决方法

数据库版本:Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi 操作系统平台:HP-UX 告警日志: more   alert_mdsoss.log 2.定位问题 报错现象: ORA-00054: resource busy acquire with nowait specified        资源忙 协成日志报错:SQL ERR :insert into table GNTCPCNN12082015     不能

MYSQL中一个特殊的MDL LOCK死锁案列

水平有限 如有错误请指出共同探讨 版本:5.7.19 mysql+innodb 本文中所说的上文是如下文章,也是讨论MDL LOCK死锁的基础,包含了很多MDL LOCK的基础知识建议 好好阅读http://blog.itpub.net/7728585/viewspace-2143093/ 一.问题由来 前段开发反馈时间线上数据库老是出现死锁情况,而我们设置了innodb_print_all_deadlocks,但是在 相应的时间点没有找到任何相应的死锁的信息,从而导致我们获得任何有用的信息,也

[MySQL 源码]MySQL5.1版本 lock table write与DML操作产生的MySQL层/Innodb层死锁

------------- 当在set autocommit=0时,执行lock table write操作,如果此时有同一个表上进入Innodb层的DML,可能导致死锁,这种死锁MySQL不做检测,只能等待Innodb层超时,简单的分析如下: 1. 对于lock table write操作,backtrace如下: SQL :set aucommit = 0 && lock tables t1 write: mysql_execute_command     –>open_and_

MYSQL INNODB replace into 死锁 及 next key lock 浅析

原创:全文带入了大量自我认知和理解,可能错误,因为水平有限,但是代表我努力分析过. 一.问题提出问题是由姜大师提出的.问题如下:表:mysql> show create table c \G*************************** 1. row ***************************       Table: cCreate Table: CREATE TABLE `c` (  `a` int(11) NOT NULL AUTO_INCREMENT,  `b` in

MySQL内核月报 2015.03-MySQL · 答疑释惑· 并发Replace into导致的死锁分析

测试版本:MySQL5.6.23 测试表: 背景 Replace into操作可以算是比较常用的操作类型之一,当我们不确定即将插入的记录是否存在唯一性冲突时,可以通过Replace into的方式让MySQL自动处理:当存在冲突时,会把旧记录替换成新的记录. 我们先来理一下一条简单的replace into操作(如上例所示)的主要流程包括哪些. Step 1. 正常的插入逻辑 首先插入聚集索引记录,在上例中a列为自增列,由于未显式指定自增值,每次Insert前都会生成一个不冲突的新值. 随后插入