行级锁有三种模式:

innodb 行级锁 record-level lock大致有三种:record lock, gap lock and Next-KeyLocks。
record lock  锁住某一行记录  
gap lock     锁住某一段范围中的记录 
next key lock 是前两者效果的叠加。

问题:

行级锁表现形式:next-key lock

错误码: 1213
Deadlock found when trying to get lock; try restarting transaction,重点在于:Deadlock FOUND WHEN trying TO get LOCK; 表示行级锁冲突

解决:

解决方案,可能该更新处于一个大表,而且,表中不断有数据插入,将会出现这样的问题,可以使用更新标识在对应的更新分组上,然后,进行多次更新数据,如果出现锁,报错,事务回滚,然后,再次进行数据更新,这个锁发生的几率不大,所以,可以使用该方法进行解决

参考博客:

innodb 行级锁 record-level lock大致有三种:record lock, gap lock and Next-KeyLocks。
record lock  锁住某一行记录  
gap lock     锁住某一段范围中的记录 
next key lock 是前两者效果的叠加。
下面是MYSQL官方文档中相关内容的链接
http://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html
【实验环境】
session 1 20:39:29> show create table gap \G
*************************** 1. row ***************************
       Table: gap
Create Table: CREATE TABLE `gap` (
  `id` int(11) DEFAULT NULL,
  KEY `ind_gap_id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
session 1 20:39:32> select * from gap;      
+------+
| id   |
+------+
|   17 |
|   20 |
|   33 |
|   39 |
|   42 |
|   43 |
+------+
6 rows in set (0.00 sec)
 
【实验】
两个会话都在REPEATABLE-READ 事务隔离级别。且都要在事务中进行。
session 1  20:39:37> start transaction;      
Query OK, 0 rows affected (0.00 sec)
session 1  20:39:41> delete from gap where id=33;
Query OK, 1 row affected (0.00 sec)
session 20:40:07> 
 
在会话2中 插入id <20 和 >=39的值 可以执行成功,而当要插入的id [20,39)的值时 会遇到gap lock 。
session 2 20:40:15> start transaction;
Query OK, 0 rows affected (0.00 sec)
session 2 20:40:30> insert into gap values(14);
Query OK, 1 row affected (0.00 sec)
session 2 20:40:59> insert into gap values(18);
Query OK, 1 row affected (0.00 sec)
session 2 20:41:06> insert into gap values(20);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 2 20:41:12> insert into gap values(24);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 2 20:42:17> 
session 2 20:42:53> insert into gap values(35); 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 2 20:44:09> 
session 2 20:44:56> insert into gap values(39);
Query OK, 1 row affected (0.00 sec)
session 2 20:45:13> insert into gap values(40);              
Query OK, 1 row affected (0.00 sec)
 
从上面的实验中可以看出会话1 执行删除语句之后,不仅仅锁住 id=33的记录,同时也锁住区间为[20,39)的记录。具体的原因是执行delete from gap where id=33语句,mysql 会执行索引扫描并在该表上施加一个next-key lock ,向左扫描到20,向右扫描到39 ,锁定区间左闭右开,所以lock的范围是 [20,39)。
 
【gap 锁带来的问题】
生产环境中有这样的一个情况:
程序会对一个表message 进行update 和insert 
session 1
UPDATE message SET gmt_modified = now(),deal_times = deal_times +1   , status = 'sending' , gmt_retry = '2012-11-17 23:54:10' 
WHERE message_id=18;
insert into  message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry) 
values ('hello !',-1,'sending','instance_status_sync',2,127,now(),now(),now());
 
session 2
UPDATE message SET gmt_modified = now(),deal_times = deal_times +1   , status = 'sending' , gmt_retry = '2012-11-17 23:54:10' 
WHERE message_id=19;
insert into  message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry) 
values          ('hello world!',-2,'sending','instance_status_sync',1,17,now(),now(),now());
 
对于上述程序在无并发情况下,运行正常,但是并发量大的情况下,执行顺序可能就会变成下面的:
UPDATE message SET gmt_modified = now(),deal_times = deal_times +1   , status = 'sending' , gmt_retry = '2012-11-17 23:54:10' 
WHERE message_id= 61;
UPDATE message SET gmt_modified = now(),deal_times = deal_times +1   , status = 'sending' , gmt_retry = '2012-11-17 23:54:10' 
WHERE message_id= 73;
insert into  message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry) 
values          ('hello world!',-2,'sending','instance_status_sync',1,17,now(),now(),now());
insert into  message (body ,user_id,status,message_type,version,deal_times,gmt_create,gmt_modified,gmt_retry) 
values ('hello !',-1,'sending','instance_status_sync',2,127,now(),now(),now()); 
此时 往往会报错
[ERROR]  Could not execute Write_rows event on table db.message; Deadlock found when trying toget lock; ; try restarting transaction, Error_code: 1213;  
 
前两条update 类型的语句都已经获得了[59,75 )区间内记录的S锁,然后两个事务又分别对该区间段内的message_id=10这个位置请求X锁,这时就发生死锁,谁都请求不到X锁,因为互相都持有S锁。
 
【解决方案有两种】
1、改变程序中数据库操作的逻辑
2、取消gap lock机制
Gap locking can be disabled explicitly.This occurs if you change the transaction isolation level to READ COMMITTED orenable the innodb_locks_unsafe_for_binlog system variable.
【参考】
http://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html
http://dev.mysql.com/doc/refman/5.1/en/innodb-locks-set.html
 

MySQL死锁原因分析的更多相关文章

  1. MySQL 死锁问题分析

    转载: MySQL 死锁问题分析 线上某服务时不时报出如下异常(大约一天二十多次):"Deadlock found when trying to get lock;". Oh, M ...

  2. MySQL死锁案例分析与解决方案

    MySQL死锁案例分析与解决方案 现象: 数据库查询: SQL语句分析:  mysql. 并发delete同一行记录,偶发死锁.   delete from x_table where id=?   ...

  3. Mysql update后insert造成死锁原因分析及解决

    系统中出现死锁的日志如下: ) TRANSACTION: , ACTIVE sec inserting mysql tables , locked LOCK WAIT lock struct(s), ...

  4. MySQL死锁问题分析及解决方法实例详解(转)

      出处:http://www.jb51.net/article/51508.htm MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1.MySQL常用 ...

  5. mysql死锁问题分析

    线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来 ...

  6. mysql死锁问题分析(转)

    线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来 ...

  7. Winform同步调用异步函数死锁原因分析、为什么要用异步

    1.前言 几年前,一个开发同学遇到同步调用异步函数出现死锁问题,导致UI界面假死.我解释了一堆,关于状态机.线程池.WindowsFormsSynchronizationContext.Post.co ...

  8. MySQL 死锁日志分析

    ------------------------ LATEST DETECTED DEADLOCK ------------------------ 140824  1:01:24 *** (1) T ...

  9. Mysql死锁如何排查:insert on duplicate死锁一次排查分析过程

    前言 遇到Mysql死锁问题,我们应该怎么排查分析呢?之前线上出现一个insert on duplicate死锁问题,本文将基于这个死锁问题,分享排查分析过程,希望对大家有帮助. 死锁案发还原 表结构 ...

随机推荐

  1. C#封装百度Web服务API处理包含(Geocoding API,坐标转换API)

    1.创建基础参数类 public static class BaiduConstParams { public const string PlaceApIv2Search = "http:/ ...

  2. Android 布局之LinearLayout 子控件weight权重的作用详析

    关于Android开发中的LinearLayout子控件权重android:layout_weigh参数的作用,网上关于其用法有两种截然相反说法: 说法一:值越大,重要性越高,所占用的空间越大: 说法 ...

  3. 图解IIS配置过程

    环境介绍: 操作系统:win7,64位.IIS7 开发软件:VS2010,32位 图解IIS配置过程: 此过程之前确保已安装了IIS. 1.在"控制面板"中找到"管理工具 ...

  4. CTabCtrl控件标签的相关设置

    原文链接: http://blog.csdn.net/happyhell/article/details/6012177 1. 获得CTabCtrl标签高度:CRect rc; CTabCtrl *p ...

  5. Python istitle() 方法

    描述 istitle() 方法检测字符串中所有的单词拼写首字母是否为大写,且其他字母为小写. 语法 istitle() 方法语法: S.istitle() 参数 无. 返回值 如果字符串中所有的单词拼 ...

  6. VC6.0编译DLL,使用VS2010调用问题及解决方法

    1.做驱动的时候.做应用程序须要和驱动通信,必须建立一个DLL. 2.由于客户使用版本号太低,须要使用到VC6.0编写DLL 3.在VC6.0上编写DLL的时候,导出的函数名会出现和原函数名不正确,导 ...

  7. sublim3常用插件安装

    1首先需要安装插件管理器Package Control,点击View > Show Console菜单,输入以下代码,按回车运行即可.说明:以下只对st3有效 import urllib.req ...

  8. 离线安装 Ambari Hadoop

    制作本地yum源 安装步骤: 先建立本地yum源(Ambari和HDP的) 1. 先安装 ambari 然后http://localhost:8080 登录进去,设置 hdp的源链接. 2. 安装HD ...

  9. 关于K8s集群器日志收集的总结

    本文介绍了kubernetes官方提供的日志收集方法,并介绍了Fluentd日志收集器并与其他产品做了比较.最后介绍了好雨云帮如何对k8s进行改造并使用ZeroMQ以消息的形式将日志传输到统一的日志处 ...

  10. 使用SQL语句的子查询批量复制表数据

    批量复制表数据这里有两种方法,下面分别来介绍这两种方法: 一.手动创建新表,然后复制数据 如果是要复制整个表的话,可以使用SQL SERVER自动生成CREATE脚本: 然后在脚本中改改表名就可以了, ...