### 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!!!还买什么课啊!!看官网干啥!愣着啊!!