最近遭遇したハイトダウン、mysql innodbエンジンのデッドロック問題を解決

3214 ワード

最近、生産環境のログを調べて、ある問題を探しているとき、ログの異常な情報を何気なく見ました.
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=?  

この3つのupdate文は、3つのウィンドウの異なるセッションで同時に実行され、デッドロックの問題が発生します.著者らは,最初のupdateを実行するとinnodbがuser_に先に与えるためであると剖析した.idインデックスにローロックを追加しitem_idのインデックスにローロックが追加されました.2番目のupdateではidのインデックスに行ロックをかけてuser_idインデックスにローロックを付ける;3つ目はまた1つ目と一致し、このとき、1つ目と2つ目は互いに相手のロックが解放されるのを待っていて、デッドロックが発生しました.
私が出会った問題はおかしいです.私が非常によく分析したログ(非常に大きく、4つのG)によると、2つのupdate文(スレッドが多く、実行回数も多いが、いずれもsqlを繰り返している)しか発見されず、唯一の2つの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はプライマリ・キーであり、このテーブルにはインデックスが確立されていないため、プライマリ・キー・インデックスのみが作成されます.
しかし、まさにこの2本のSqlがデッドロックを起こした!私は推測と排除法を取って目標をロックして、私は第2条のsqlの実現を先にビジネスによってa_を検索するように変更しました.t_id,さらにa_によるt_idは更新され、第1条のように、
この時、奇跡が起こり、同時に300スレッドの圧力テストを行った場合、デッドロックの異常は報告されなくなった.前に、10個のスレッドが一例を報告しました!
私のこのシーンは前の仁兄が出会ったのとあまり一致していません.結局、私のところには他のインデックスがありません.だから、今まで、なぜそうなったのか分かりませんでした.しかし、この厄介な問題を解決し、mysqlにこのような穴があることを知ってから避けることができて、私は依然としてとても楽しかったです~!