您的位置:首页 > 数据库 > MySQL

解决最近遇到的高并发下,mysql innodb引擎的死锁问题

2015-11-16 21:02 881 查看
最近在查生产环境上的日志,找某个问题的时候,无意中瞟见了日志中的一个异常信息:

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有这样一类坑以后可以避免,我仍然感觉非常愉快~!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: