解决最近遇到的高并发下,mysql innodb引擎的死锁问题
2015-11-16 21:02
881 查看
最近在查生产环境上的日志,找某个问题的时候,无意中瞟见了日志中的一个异常信息:
,于是将这个问题记下,直到解决了刚说的前一个问题之后才腾出功夫看看这个异常信息。
从日志上来看,是innoDB出现了死锁的情况。
由于我真的没什么mysql经验,于是度娘了一番,又翻墙谷哥了一下,找到一些相关资料。
我猜测此问题是由于innoDB的行锁导致的,但是又和我所查到的博客上介绍的案例不太一致:博客上的案例给的例子是
此三个update语句用三个窗口不同session同时执行,于是,死锁问题就产生了。产生的原因,作者剖析是,当执行第一个update时,innodb先给user_id索引加了行锁,然后给item_id的索引加了行锁;第二个update时,给id的索引加了行锁,再给user_id索引加行锁;第三个又和第一个一致,此时,第一个与第二个就互相等待对方的锁释放了,死锁便发生了。
而我碰到的问题则比较奇怪,因为据我非常仔细的分析日志(非常大,4个G),只发现了两条update语句(线程很多,执行次数也很多,但都是重复sql),唯一这两条sql一路排查下来,引起了我的怀疑。
a_t_id为主键,此表没有建立任何索引,所以只有主键索引。
但是,正是这两条Sql引起了死锁!我是采取的猜测加排除法来锁定目标的,我将第二条sql的实现改为了先根据busines查找a_t_id,再根据a_t_id来进行更新,像第一条一样,
这时候,奇迹发生了,同时300个线程进行压力测试的情况下,竟然不再报死锁的异常了。之前,10个线程就报了一例!
我这个场景和前一位仁兄所遇到的并不太一致,毕竟我这里没有其它的索引,所以,到目前为止,我也没搞明白为什么会如此。但是,能解决这个棘手的问题,并且知道mysql有这样一类坑以后可以避免,我仍然感觉非常愉快~!
16:17:39.420 [http-58080-207] DEBUG o.a.f.w.h.AppSimpleMappingExceptionResolver:132 - Resolving exception from handler [public org.anrhd.framework.domain.AppMap org.anrhd.framework.web.remote.DomainController.doAction(java.lang.String,java.lang.String,org.anrhd.framework.domain.AppMap,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException]: java.lang.RuntimeException: java.lang.RuntimeException: org.springframework.dao.DeadlockLoserDataAccessException: SqlMapClient operation; SQL []; --- The error occurred in org/anrhd/framework/dao/ibatis/criteria_SqlMap.xml. --- The error occurred while applying a parameter map. --- Check the user_acct_tran.insert-InlineParameterMap. --- Check the statement (update failed). --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in org/anrhd/framework/dao/ibatis/criteria_SqlMap.xml. --- The error occurred while applying a parameter map. --- Check the user_acct_tran.insert-InlineParameterMap. --- Check the statement (update failed). --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
,于是将这个问题记下,直到解决了刚说的前一个问题之后才腾出功夫看看这个异常信息。
从日志上来看,是innoDB出现了死锁的情况。
由于我真的没什么mysql经验,于是度娘了一番,又翻墙谷哥了一下,找到一些相关资料。
我猜测此问题是由于innoDB的行锁导致的,但是又和我所查到的博客上介绍的案例不太一致:博客上的案例给的例子是
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 update user_item set status=1 where user_id=? and item_id=? update user_item.....where id=?and user_id=? update user_item set status=1 where user_id=? and item_id=?
此三个update语句用三个窗口不同session同时执行,于是,死锁问题就产生了。产生的原因,作者剖析是,当执行第一个update时,innodb先给user_id索引加了行锁,然后给item_id的索引加了行锁;第二个update时,给id的索引加了行锁,再给user_id索引加行锁;第三个又和第一个一致,此时,第一个与第二个就互相等待对方的锁释放了,死锁便发生了。
而我碰到的问题则比较奇怪,因为据我非常仔细的分析日志(非常大,4个G),只发现了两条update语句(线程很多,执行次数也很多,但都是重复sql),唯一这两条sql一路排查下来,引起了我的怀疑。
update user_acct_tran set status =?,balance=?,amount=? where a_t_id=? and status='03' update user_acct_tran set status =? ,balance=?,amount=? where busines=? and status='03'
a_t_id为主键,此表没有建立任何索引,所以只有主键索引。
但是,正是这两条Sql引起了死锁!我是采取的猜测加排除法来锁定目标的,我将第二条sql的实现改为了先根据busines查找a_t_id,再根据a_t_id来进行更新,像第一条一样,
这时候,奇迹发生了,同时300个线程进行压力测试的情况下,竟然不再报死锁的异常了。之前,10个线程就报了一例!
我这个场景和前一位仁兄所遇到的并不太一致,毕竟我这里没有其它的索引,所以,到目前为止,我也没搞明白为什么会如此。但是,能解决这个棘手的问题,并且知道mysql有这样一类坑以后可以避免,我仍然感觉非常愉快~!
相关文章推荐
- mysql初步备份方案
- 分享一个VBA连接mysql数据库的方法
- ubuntu 14.04 安装mysql
- [mysql]explain语句中的key_len计算
- mysqlslap压力测试
- 我的mysql使用心得
- MySQL show processlist 中status
- MySQLdb数据库操作
- mysql 远程连接
- MYSQL查询语句大全集锦
- MYSQL一次调优经验
- mysql的主从配置
- SQL.Mysql中Cast()函数的用法
- MySql变量,
- mysql忘记root密码拯救方法(flush privileges)
- MySQL索引原理及慢查询优化
- mysql保障数据一致性:锁与解(一)
- mysql 查看版本的四种方法
- 关于 未能加载文件或程序集“MySql.Web, Version=6.7.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d”或它的某一个依赖项。系统找不到指定的文件。
- MySQL 锁