MySQL死锁排查

JAVA程序

JSTACK或者JVISUALVM都能自动检查程序死锁

数据库命令

show engine innodb status


image.png

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象。正常死锁会自动释放,innodb有一个内在的死锁检测工具,当死锁超过一定时间后,会回滚其中一个事务,innodb_lock_wait_timeout可配置死锁等待超时时间。
死锁日志案例如下:

------------------------

LATEST DETECTED DEADLOCK

------------------------

111109 20:10:03

*** (1) TRANSACTION:

TRANSACTION 65839, ACTIVE 19 sec, OS thread id 4264 starting index read

mysql tables in use 1, locked 1

LOCK WAIT 6 lock struct(s), heap size 1024, 3 row lock(s), undo log entries 1

MySQL thread id 3, query id 74 localhost 127.0.0.1 root Updating

UPDATE parent SET age=age+1 WHERE id=1

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 6833 page no 3 n bits 72 index `PRIMARY` of table

`test`.`parent` trx id 65839 lock_mode X locks rec but not gap waiting

Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0

*** (2) TRANSACTION:

TRANSACTION 65838, ACTIVE 26 sec, OS thread id 768 starting index read,

thread declared inside InnoDB 500

mysql tables in use 1, locked 1

7 lock struct(s), heap size 1024, 4 row lock(s), undo log entries 2

MySQL thread id 4, query id 75 localhost 127.0.0.1 root Updating

UPDATE parent SET age=age+1 WHERE id=2

*** (2) HOLDS THE LOCK(S):

RECORD LOCKS space id 6833 page no 3 n bits 72 index `PRIMARY` of table

`test`.`parent` trx id 65838 lock_mode X locks rec but not gap

Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 6833 page no 3 n bits 72 index `PRIMARY` of table

`test`.`parent` trx id 65838 lock_mode X locks rec but not gap waiting

Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0

*** WE ROLL BACK TRANSACTION (1)

数据库避免死锁

  • 合理的设计索引,区分度高的列放到组合索引前面,使业务 SQL 尽可能通过索引定位更少的行,减少锁竞争。
  • 调整业务逻辑 SQL 执行顺序, 避免 update/delete 长时间持有锁的 SQL 在事务前面。
  • 避免大事务,尽量将大事务拆成多个小事务来处理,小事务发生锁冲突的几率也更小。
  • 以固定的顺序访问表和行。比如两个更新数据的事务,事务 A 更新数据的顺序为 1,2;事务 B 更新数据的顺序为 2,1。这样更可能会造成死锁。
  • 在并发比较高的系统中,不要显式加锁,特别是是在事务里显式加锁。如 select … for update 语句,如果是在事务里(运行了 start transaction 或设置了autocommit 等于0),那么就会锁定所查找到的记录。
  • 尽量按主键/索引去查找记录,范围查找增加了锁冲突的可能性,也不要利用数据库做一些额外额度计算工作。比如有的程序会用到 “select … where … order by rand();”这样的语句,由于类似这样的语句用不到索引,因此将导致整个表的数据都被锁住。
  • 优化 SQL 和表设计,减少同时占用太多资源的情况。比如说,减少连接的表,将复杂 SQL 分解为多个简单的 SQL。

你可能感兴趣的:(MySQL死锁排查)