MYSQL中的死锁:如何找出为什么无法获取锁?

时间:2018-07-28 08:42:38

标签: mysql deadlock

以下情况会导致死锁,如SHOW INNODB STATUS结果所示:

  • Transaction1尝试更新id = 5的mytable并等待 X
  • 类型的行锁定记录
  • Transaction2试图更新mytable,其中id = 5保留类型为 S 的行锁定记录,并等待类型为 X
  • 的行锁定记录

两个事务中没有一个实际上拥有正确的记录,因此我们无法真正理解为什么这会导致死锁,除非存在拥有该锁并且也死锁的第三笔事务。如何对此问题进行进一步调查,并以某种方式将其与触发因素联系起来?

LATEST DETECTED DEADLOCK
------------------------
2018-07-28 08:27:08 0x7f1a08537700
*** (1) TRANSACTION:
TRANSACTION 2183, ACTIVE 0 sec starting index read
mysql tables in use 5, locked 5
LOCK WAIT 7 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 47, OS thread handle 139750051079936, query id 1481 172.24.0.1 myuser updating
update `mytable` set `status` = 'OK' where `mytable`.`id` = 5
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `mydb`.`mytable` trx id 2183 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 000000000885; asc       ;;
 2: len 7; hex 2c0000018b0110; asc ,      ;;
 3: len 30; hex 66643164396162382d663462642d343237652d626461362d316430626634; asc fd1d9ab8-f4bd-427e-bda6-1d0bf4; (total 36 bytes);
 4: len 4; hex 5b5c28d7; asc [\( ;;
 5: len 4; hex 5b5c28dc; asc [\( ;;
 6: len 6; hex 80000186a000; asc       ;;
 7: len 4; hex 80000005; asc     ;;
 8: len 3; hex 455552; asc EUR;;
 9: len 4; hex 80000001; asc     ;;
 10: len 17; hex 52454144595f464f525f414456414e4345; asc OK;;
 11: SQL NULL;
 12: len 3; hex 8fc55a; asc   Z;;
 13: len 3; hex 8fc55a; asc   Z;;
 14: SQL NULL;
 15: len 15; hex 30303141307965644562686c466966; asc 001A0yedEbhlFif;;
 16: SQL NULL;
 17: len 1; hex 80; asc  ;;

*** (2) TRANSACTION:
TRANSACTION 2187, ACTIVE 0 sec starting index read
mysql tables in use 5, locked 5
7 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 50, OS thread handle OK, query id 1482 172.24.0.1 myuser updating
update `mytable` set `status` = 'OK' where `mytable`.`id` = 5
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `mydb`.`mytable` trx id 2187 lock mode S locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 000000000885; asc       ;;
 2: len 7; hex 2c0000018b0110; asc ,      ;;
 3: len 30; hex 66643164396162382d663462642d343237652d626461362d316430626634; asc fd1d9ab8-f4bd-427e-bda6-1d0bf4; (total 36 bytes);
 4: len 4; hex 5b5c28d7; asc [\( ;;
 5: len 4; hex 5b5c28dc; asc [\( ;;
 6: len 6; hex 80000186a000; asc       ;;
 7: len 4; hex 80000005; asc     ;;
 8: len 3; hex 455552; asc EUR;;
 9: len 4; hex 80000001; asc     ;;
 10: len 17; hex 52454144595f464f525f414456414e4345; asc OK;;
 11: SQL NULL;
 12: len 3; hex 8fc55a; asc   Z;;
 13: len 3; hex 8fc55a; asc   Z;;
 14: SQL NULL;
 15: len 15; hex 30303141307965644562686c466966; asc 001A0yedEbhlFif;;
 16: SQL NULL;
 17: len 1; hex 80; asc  ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `mydb`.`mytable` trx id 2187 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 000000000885; asc       ;;
 2: len 7; hex 2c0000018b0110; asc ,      ;;
 3: len 30; hex 66643164396162382d663462642d343237652d626461362d316430626634; asc fd1d9ab8-f4bd-427e-bda6-1d0bf4; (total 36 bytes);
 4: len 4; hex 5b5c28d7; asc [\( ;;
 5: len 4; hex 5b5c28dc; asc [\( ;;
 6: len 6; hex 80000186a000; asc       ;;
 7: len 4; hex 80000005; asc     ;;
 8: len 3; hex 455552; asc EUR;;
 9: len 4; hex 80000001; asc     ;;
 10: len 17; hex 52454144595f464f525f414456414e4345; asc OK;;
 11: SQL NULL;
 12: len 3; hex 8fc55a; asc   Z;;
 13: len 3; hex 8fc55a; asc   Z;;
 14: SQL NULL;
 15: len 15; hex 30303141307965644562686c466966; asc 001A0yedEbhlFif;;
 16: SQL NULL;
 17: len 1; hex 80; asc  ;;

*** WE ROLL BACK TRANSACTION (2)

1 个答案:

答案 0 :(得分:0)

第二个事务确实拥有共享(public class SQLTableImport { //***********Constructor for Filter Table export (2 columns Check box and string)********** public SQLTableImport(String descriptionColumn){ if(getSqlSelectedType().equals("BLOB")){ setSql("SELECT DISTINCT "+getSqlColumnName()+" , "+descriptionColumn+" FROM `"+ getTableName() +"`"+whereClause+""); } else{ setSql("SELECT DISTINCT "+getSqlColumnName()+" FROM `"+ getTableName() +"`"+whereClause+""); } } //***********METHOD FOR RETURNING THE MODEL FOR A FILTER FRAME 1 COLUMN AND 1 CHECKBOX COLUMN public DefaultTableModel getFilterModelFromSqlTable(){ if(getSqlSelectedType().equals("BLOB")){emptyHeaders= new Object[][]{null,null,null};} DefaultTableModel dFilterTableModel = new DefaultTableModel(emptyrows, emptyHeaders){ private static final long serialVersionUID = 1L; @Override public boolean isCellEditable(int row, int column) { return column == 0; } public Class <?> getColumnClass(int column) { if(column==0){ return Boolean.class; } if(column==2){ return String.class; } switch (getSqlColumnType()[CustomTable.getColumnIndex()]) { case "VARCHAR": return String.class; case "INT": return Integer.class; case "DECIMAL": return Double.class; case "DATE": return Date.class; case "TINYINT": return String.class; case "BLOB": return Icon.class; default: return Object.class; } } }; try { setPst(Utilities.sqlConnnect().prepareStatement(getSql())); setRs(getPst().executeQuery(getSql())); java.sql.ResultSetMetaData tempResult = getPst().getMetaData(); int tempColumnCount = tempResult.getColumnCount(); Object[] tempRow= new Object[tempColumnCount+1]; while(getRs().next()){ // Gets the column values based on class type expected tempRow[0]= false; if(getSqlColumnType()[CustomTable.getColumnIndex()].equals("VARCHAR")){ tempRow[tempColumnCount]= getRs().getString(tempColumnCount); } if(getSqlColumnType()[CustomTable.getColumnIndex()].equals("INT")){ tempRow[tempColumnCount]= getRs().getInt(tempColumnCount); } if(getSqlColumnType()[CustomTable.getColumnIndex()].equals("DECIMAL")){ tempRow[tempColumnCount]= getRs().getDouble(tempColumnCount); } if(getSqlColumnType()[CustomTable.getColumnIndex()].toString().equals("DATE")){ } if(getSqlColumnType()[CustomTable.getColumnIndex()].equals("TINYINT")){ tempRow[tempColumnCount]= getRs().getBoolean(tempColumnCount); } if(getSqlColumnType()[CustomTable.getColumnIndex()].equals("BLOB")){ Blob blob = getRs().getBlob(tempColumnCount-1); ImageIcon icon = null; try (InputStream is = blob.getBinaryStream()) { BufferedImage img = ImageIO.read(is); icon = new ImageIcon(img.getScaledInstance(17, 17, Image.SCALE_SMOOTH)); } tempRow[tempColumnCount-1] =icon; tempRow[tempColumnCount]= getRs().getString(tempColumnCount); } // Adds the row of data to the end of the model dFilterTableModel.addRow(tempRow); } } catch (Exception e) { JOptionPane.showMessageDialog(null,e); } finally { try { getPst().close(); getRs().close(); } catch (SQLException e1) { JOptionPane.showMessageDialog(null,e1); } } return dFilterTableModel;} )锁,这防止了第一个事务获得独占(S)锁。

但是mysql注册了第一个事务想要一个排他锁,该锁进入了队列。

然后第二个事务想要将锁升级为独占锁,这是不可以的,因为第一笔事务已经注册了其独占锁的意图。

这是mysql中死锁的教科书案例,请参见mysql手册中的14.5.5.1 An InnoDB Deadlock Example部分