### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction ### The error may involve com.cgd.order.dao.OrderSaleMapper.updateSaleOrderStatus-Inline ### The error occurred while setting parameters ### SQL: update t_order set ORDER_STATUS = ? where ORDER_ID = ?
小盆友,若是你在日誌裏看到這個是否是像我同樣會有不少問號??
我一個只會寫增刪改查sql的低層次程序員有了滿奶子問號。
可是我相信啊:只要功夫深,李白碰到的老婆婆就能把鐵杵磨成針。html
從極客上找了門MySQL實戰,若是你也想買,請聯繫我,推薦人買有返現的。 mysql
這門課我是以爲很值,這兩天爲了解決這個死鎖又讀了一遍有關加鎖的章節,發現了一條命令啊,這個命令會輸出不少信息,有一節 LATESTDETECTED DEADLOCK,就是記錄的最後一次死鎖信息。程序員
show engine innodb status;
我就試着執行了下,好巧不巧跟那天死鎖日誌裏的sql同樣,不過也說明這死鎖問題挺頻繁的sql
------------------------ LATEST DETECTED DEADLOCK ------------------------ 2020-12-17 11:20:09 7fbe339f7700 //第一個事務 *** (1) TRANSACTION: TRANSACTION 116609954, ACTIVE 1.214 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s) LOCK BLOCKING MySQL thread id: 72830 block 64282 MySQL thread id 64282, OS thread handle 0x7fbe01f7d700, query id 1042364621 172.16.21.10 prod_orderdb updating //以上亂七八糟的有事務的基礎信息 大小 行數等等 //下邊一行是死鎖的其中一方的sql 解析一下ORDER_ID是表的主鍵 /* 276aedd616081752079448345e2ac7/0.1.3// */ update t_order set ORDER_STATUS = 4 where ORDER_ID = 234 //表示這個事務在等待的鎖信息 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: //當前在等待表t_order上的 X鎖, 主鍵爲 8de0b6b3a773935b RECORD LOCKS space id 1252 page no 10646 n bits 112 index `PRIMARY` of table `t_order` trx id 116609954 lock_mode X locks rec but not gap waiting //n_fields 115 表示記錄有115列 Record lock, heap no 10 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 //第一列 基本就是主鍵了 0: len 8; hex 8de0b6b3a773935b; asc s [;; 1: len 6; hex 000006ef0a51; asc Q;; 2: len 7; hex 76000006f723b0; asc v # ;; 3: len 16; hex 32303230313231323030333139363331; asc 2020121200319631;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; 6: len 4; hex 80000002; asc ;; 7: SQL NULL; 8: len 4; hex 8000000b; asc ;; . ..省略1xx行 . //第二個事務信息 *** (2) TRANSACTION: TRANSACTION 116609912, ACTIVE 7.886 sec fetching rows mysql tables in use 1, locked 1 36461 lock struct(s), heap size 3241512, 306688 row lock(s), undo log entries 12 MySQL thread id 72830, OS thread handle 0x7fbe339f7700, query id 1042364593 172.16.21.0 prod_orderdb Searching rows for update //同理第二個sql update t_order set ORDER_STATUS = 4 where EXT_ID = '232SA' //當前事務持有的鎖 *** (2) HOLDS THE LOCK(S): //持有N個S鎖 RECORD LOCKS space id 1252 page no 10646 n bits 112 index `PRIMARY` of table `t_order` trx id 116609912 lock mode S locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 0: len 8; hex 8de0b6b3a7739342; asc s B;; 1: len 6; hex 000006f1aeff; asc ;; 2: len 7; hex 64000006ce20bb; asc d ;; 3: len 16; hex 32303230313231323030333139363036; asc 2020121200319606;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; 6: len 4; hex 80000002; asc ;; 7: SQL NULL; . . . //++++++++++ Record lock, heap no 10 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 0: len 8; hex 8de0b6b3a773935b; asc s [;; 1: len 6; hex 000006ef0a51; asc Q;; 2: len 7; hex 76000006f723b0; asc v # ;; 3: len 16; hex 32303230313231323030333139363331; asc 2020121200319631;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; . . . //++++++++++ 此處還省略N多 //++++++++++之間的行,同時持有不少行的鎖 //等待的鎖 *** (2) WAITING FOR THIS LOCK TO BE GRANTED: //一樣是等待X鎖 主鍵爲 8de0b6b3a773935b RECORD LOCKS space id 1252 page no 10646 n bits 112 index `PRIMARY` of table `t_order` trx id 116609912 lock_mode X locks rec but not gap waiting Record lock, heap no 10 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 0: len 8; hex 8de0b6b3a773935b; asc s [;; 1: len 6; hex 000006ef0a51; asc Q;; 2: len 7; hex 76000006f723b0; asc v # ;; 3: len 16; hex 32303230313231323030333139363331; asc 2020121200319631;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; . . . //數據庫選擇回滾成本最小的一個事務進行回滾 *** WE ROLL BACK TRANSACTION (1)
兩條sql,對應兩條數據,八竿子打不着的兩條數據在更新的時候發生了死鎖數據庫
update t_order set ORDER_STATUS = 4 where ORDER_ID = 234 update t_order set ORDER_STATUS = 4 where EXT_ID = '232SA'
當前問題所處環境整理:app
極客的課程確定細緻不到官網,因此我去官網搜了搜,由於英語不是很好,就搜了Lock關鍵字,把搜出來的文章挨個看了下,先看這個
https://dev.mysql.com/doc/ref...fetch
有條件的看原文
沒條件的看這 咱們只看讀提交部分: 對於UPDATE或 DELETE語句, InnoDB僅對其更新或刪除的行持有鎖。 MySQL評估WHERE條件後,將釋放不匹配行的記錄鎖。 這大大下降了死鎖的可能性,可是仍然能夠發生。 對於UPDATE語句,若是某行已被鎖定,則InnoDB 執行「semi-consistent」讀取, 將最新的提交版本返回給MySQL,以便MySQL能夠肯定該行是否符合 WHERE條件 UPDATE。 若是該行匹配(必須更新),則MySQL會再次讀取該行,這一次將InnoDB其鎖定或等待對其進行鎖定。
官網例子spa
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB; INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2); COMMIT; 在這種狀況下,表沒有索引,所以搜索和索引掃描使用隱藏的彙集索引進行記錄鎖定(請參見第15.6.2.1節「彙集索引和二級索引」),而不是使用索引列。 假設一個會話UPDATE使用如下語句執行 : # Session A START TRANSACTION; UPDATE t SET b = 5 WHERE b = 3; 還假設第二個會話 UPDATE經過在第一個會話的語句以後執行如下語句來執行: # Session B UPDATE t SET b = 4 WHERE b = 2; 在InnoDB執行UPDATE,它首先爲每一行獲取一個排他鎖,而後肯定是否對其進行修改。若是InnoDB不修改該行,則釋放鎖。不然,InnoDB保留該鎖直到事務結束。這會影響事務處理,以下所示。 使用默認REPEATABLE READ 隔離級別時: 第一個UPDATE將在其讀取的每一行上得到一個寫(x-lock)鎖,而且不會釋放其中的任何一個: x-lock(1,2); retain x-lock x-lock(2,3); update(2,3) to (2,5); retain x-lock x-lock(3,2); retain x-lock x-lock(4,3); update(4,3) to (4,5); retain x-lock x-lock(5,2); retain x-lock 第二UPDATE個嘗試獲取任何鎖的塊(由於第一個更新在全部行上都保留了鎖),而且直到第一個UPDATE提交或回滾時才繼續執行: x-lock(1,2); block and wait for first UPDATE to commit or roll back 使用READ COMMITTED則有不一樣: 第一個UPDATE將在讀取的每一行上獲取一個寫(x-lock)鎖,併爲未修改的行釋放x鎖: x-lock(1,2); unlock(1,2) x-lock(2,3); update(2,3) to (2,5); retain x-lock x-lock(3,2); unlock(3,2) x-lock(4,3); update(4,3) to (4,5); retain x-lock x-lock(5,2); unlock(5,2) 第二個UPDATE, InnoDB執行 「semi-consistent」讀取,將讀取的每一行的最新提交版本返回給MySQL,以便MySQL能夠肯定該行是否符合如下 WHERE條件 UPDATE: x-lock(1,2); update(1,2) to (1,4); retain x-lock x-lock(2,3); unlock(2,3) x-lock(3,2); update(3,2) to (3,4); retain x-lock x-lock(4,3); unlock(4,3) x-lock(5,2); update(5,2) to (5,4); retain x-lock 可是,若是WHERE條件包括索引列並InnoDB使用索引,則在獲取和保留記錄鎖時僅考慮索引列。
看完了例子:雖然"semi-consistent讀取"的解釋還有點迷糊,可是個人死鎖問題已經大體有了眉目。
個人表EXT_ID就是沒有索引啊,explain了,確實是全表查的,也就是存在這個一個逐行加鎖並釋放鎖的過程。rest
固然後來又發現了另外一篇文檔
https://dev.mysql.com/doc/ref...日誌
有條件的看原文去
沒條件的繼續 : 如下示例說明了鎖定請求將致使死鎖時如何發生錯誤。該示例涉及兩個客戶端A和B。 首先,客戶端A建立一個包含一行的表,而後開始事務。 在事務中,A經過S lock 下選擇行來得到對行的鎖定: mysql> CREATE TABLE t (i INT) ENGINE = InnoDB; Query OK, 0 rows affected (1.07 sec) mysql> INSERT INTO t (i) VALUES(1); Query OK, 1 row affected (0.09 sec) mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE i = 1 FOR SHARE; +------+ | i | +------+ | 1 | +------+ 接下來,客戶端B開始事務並嘗試從表中刪除該行: mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> DELETE FROM t WHERE i = 1; 刪除操做須要一個X鎖,可是它沒法得到X鎖,由於A目前持有S鎖,兩個鎖不兼容 ,所以該請求進入針對行和客戶端B塊的鎖請求隊列中。 最後,客戶端A還嘗試從表中刪除該行: mysql> DELETE FROM t WHERE i = 1; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 此處發生死鎖是由於客戶端A須要X鎖才能刪除該行。 可是,不能授予它X鎖,由於客戶端B已經有一個X鎖定請求,而且正在等待客戶端A釋放其S鎖定。 因爲B事先要求鎖,因此A持有的S 鎖也不能升級X鎖。 結果, InnoDB爲其中一個客戶端生成錯誤並釋放其鎖。客戶端返回此錯誤: ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 再以後就能夠授予對另外一個客戶端的鎖定請求,並從表中刪除該行。
我只能說這例子跟個人一毛同樣啊,早找到這篇文章我還查個屁的隔離級別。
官方文檔仍是牛B!!!還買什麼課啊!!看官網幹啥!愣着啊!!