`

mysql死锁-非主键索引更新引起的死锁

阅读更多
背景:最近线上经常抛出mysql的一个Deadlock,细细查来,长了知识!


分析:错误日志如下:
21:02:02.563 ERROR dao.CommonDao        [pool-15-thread-19] [jbc.trade.qunar.com] [703c9ddbe4b143609035365ca46bff35] - db error , tableId=jbc.trade.qunar.com, sql=update i_pay_record set checktime = now() where order_id in (62818) , par
ams=null
com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
      
其中sql更新语句:
update i_pay_record set checktime = now() where order_id in (62818)

很奇妙吧,执行一条sql会有死锁吗?
答案是:会有。

其中奥妙就在 i_pay_record 中的 order_id 字段有索引。

特此转载下面这篇文章很好的讲解了这个问题 !!!
http://blog.csdn.net/aesop_wubo/article/details/8286215
转载:
表结构如下:
CREATE TABLE `user_item` (
  `id` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) NOT NULL,
  `item_id` BIGINT(20) NOT NULL,
  `status` TINYINT(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_1` (`user_id`,`item_id`,`status`)
) ENGINE=INNODB DEFAULT CHARSET=utf-8


SQL语句如下:
update user_item set status=1 where user_id=? and item_id=?  


原因分析
mysql的事务支持与存储引擎有关,MyISAM不支持事务,INNODB支持事务,更新时采用的是行级锁。这里采用的是INNODB做存储引擎,意味着会将update语句做为一个事务来处理。前面提到行级锁必须建立在索引的基础,这条更新语句用到了索引idx_1,所以这里肯定会加上行级锁。
行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。
这个update语句会执行以下步骤:
1、由于用到了非主键索引,首先需要获取idx_1上的行级锁
2、紧接着根据主键进行更新,所以需要获取主键上的行级锁;
3、更新完毕后,提交,并释放所有锁。
如果在步骤1和2之间突然插入一条语句:update user_item .....where id=? and user_id=?,这条语句会先锁住主键索引,然后锁住idx_1。
蛋疼的情况出现了,一条语句获取了idx_1上的锁,等待主键索引上的锁;另一条语句获取了主键上的锁,等待idx_1上的锁,这样就出现了死锁。

解决方案
1、先获取需要更新的记录的主键
select id from user_item where user_id=? and item_id=?  

2、逐条更新
select id from user_item where user_id=? and item_id=?  
for (Long id : idList) {  
    userItemDAO.updateStatus(id, userId, 1);  
}  
update user_item set status=? where id=? and user_id=?  

3、这样貌似解决了,都是对单条进行操作,都是先获取主键上的锁,再获取idx_1上的锁。
不过这个解决方案与先前的更新语句不一样,先前的更新语句对所有记录的更新在一个事务中,采用循环更新后并不在同一个事务中,所以在for循环外面还得开一个事务。

Exception e = (Exception)getDbfeelTransactionTemplate().execute(new TransactionCallback() {
   public Object doInTransaction(TransactionStatus status) {
      try {
        	for(Long id:idList) {
		<span style="white-space:pre">	</span>userItemDAO.updateStatus(id,userId,1)
		}
      		return null;
      }catch(DAOException e) {
         status.setRollbackOnly();
         return e;
      }
      catch (Exception e) {
         status.setRollbackOnly();
         return e;
      }
   }
});


小结:在采用INNODB的MySQL中,更新操作默认会加行级锁,行级锁是基于索引的,在分析死锁之前需要查询一下mysql的执行计划,看看是否用到了索引,用到了哪个索引,对于没有用索引的操作会采用表级锁。如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁,否则加锁顺序相反。在并发度高的应用中,批量更新一定要带上记录的主键,优先获取主键上的锁,这样可以减少死锁的发生。
0
0
分享到:
评论

相关推荐

    初学者从源码理解MySQL死锁问题

    场景1:通过主键进行删除 表结构 CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB; delete from t1 where

    当Mysql行锁遇到复合主键与多列索引详解

    主要给大家介绍了关于当Mysql行锁遇到复合主键与多列索引的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Mysql具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    mysql面试题(涉及索引、事务、锁)

    MySQL遇到的死锁问题、如何排查与解决 索引类别(B+树索引、全文索引、哈希索引)、索引的原理 什么是自适应哈希索引(AHI) 遇到过索引失效的情况没,什么时候可能会出现,如何解决 如何选择合适的分布式主键方案 ...

    100道mysql的面试题

    2. 文档内容包括mysql索引,索引失效,覆盖索引,回表,二叉树,死锁,读写分离,分库分表,分库分表中间件,聚集索引或非聚集索引, 索引优化,事务级别,幻读,脏读,不可重复读,数据库的乐观锁和悲观锁,SQL优化...

    mysql面试题100题,包含答案和解析.docx

    2、MySQL 遇到过死锁问题吗,你是如何解决的? 3、日常工作中你是怎么优化SQL的? 4、InnoDB与MyISAM的区别 5、数据库索引的原理,为什么要用 B+树,为什么不用二叉树? 6、聚集索引与非聚集索引的区别 7、limit ...

    MySQL数据库面试题(50道题含答案和思维导图总结)

    关于MySQL常见的知识点总结了一个思维导图分享给大家,希望对大家有所帮助! 1、MySQL 中有哪几种锁? (1)表级锁:开销小,加锁快;不会出现死锁;...(6)主键索引采用聚集索引索引的数据域存储数据

    Mysql 数据库死锁过程分析(select for update)

    近期有一个业务需求,多台机器需要同时从Mysql一个表里查询数据并做后续业务逻辑,为了防止多台机器同时拿到一样的数据,每台机器需要在获取时锁住获取数据的数据段,保证多台机器不拿到相同的数据。 我们Mysql的...

    18道经典 MySQL 面试题.txt

    18道经典 MySQL 面试题。1、用一句话介绍什么是MySQL?2、对MySQL数据库去重的关键字是什么?3、MySQL多表连接有哪些方式?怎么用的?这些连接都有什么区别?4、MySQL数据库和Redis的区别?5、说一下索引的优势和...

    MySQL详解视频.zip

    主键索引 唯一索引 单列索引 多列索引 索引使用角度 覆盖索引 索引下推 oMySql架构设计之Innodb深入解剖 Buffer Pool Free链表 Flush链表 Lru链表 Redo Log log buffer 事务提交 Undo...

    interview:面试题目汇集

    vs 死锁索引索引类型数据结构角度B TreeHash索引从逻辑角度主键索引普通索引唯一索引复合索引全文索引使用原则聚簇索引和非聚簇索引问题优化慢查询explain 详解idselect_typetabletypepossible_keysKeykey_...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    在创建表时,经常会创建该表的主键、外键、唯一约束、Check约束等  语法结构 create table 表名( [字段名] [类型] [约束] ……….. CONSTRAINT fk_column FOREIGN KEY(column1,column2,…..column_n) ...

    asp.net知识库

    简单实用的DataSet更新数据库的类+总结 [ADO.NET]由数据库触发器引发的问题 为ASP.NET封装的SQL数据库访问类 DataTable.Select方法的性能问题 .NET 2.0里使用强类型数据创建多层应用 ADO.NET实用经验无保留曝光 有了...

    JAVA上百实例源码以及开源项目

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    JAVA上百实例源码以及开源项目源代码

    Java 3DMenu 界面源码 5个目标文件 内容索引:Java源码,窗体界面,3DMenu Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都...

Global site tag (gtag.js) - Google Analytics