MySQL一次死锁的问题

 一个线上系统,稳定运行了一段时间后突然出现一些死锁情况,程序抛异常类似于下面这样:

  
  
  
  
  1. com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction 
  2.         at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
  3.         at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39
  4.         at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27
  5.         at java.lang.reflect.Constructor.newInstance(Constructor.java:513
  6.         at com.mysql.jdbc.Util.handleNewInstance(Util.java:406
  7.         at com.mysql.jdbc.Util.getInstance(Util.java:381
  8.         at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1045
  9.         at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956
  10.         at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491
  11.         at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423

导致出现问题的SQL是这样的

  
  
  
  
  1. insert into xxx (...) 
  2.     select aaa, bbb from dual where not exists ( 
  3.         select * from xxx where aaa = yyy 
  4.     ) 

这是一个我们很常见的场景:先查下某条数据是否存在,若不存在就插入一条。

之所以sql这样写,是为了防止高并发情况下发生唯一性约束冲突的异常,这种先select再insert的写法,被称作conditional insert。这里有一个潜在问题就是内层select会加锁,如果此时另外一个线程也进行查询操作,会直接deadlock。

解决办法也很粗暴:

直接insert,不带任何条件,然后程序里面做下容错,将所有唯一性约束的异常吃掉。

MySQL里面有很多这样看上去很美的写法和功能,真正用了才发现自己掉坑里了。生产环境,还是保守一点好。

你可能感兴趣的:(mysql,死锁)