MySQL 出现死锁的分析和解决方案

摘要: 公司有提现业务,此提现业务比较复杂,有添加、有更新,所以加了事务,但是在运行了一段时间后出现了死锁异常。 通过查看日志,最终分析出了原因,并解决问题,写此不可,方便后来人少走弯路

异常日志

### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

### The error may involve defaultParameterMap

### The error occurred while setting parameters

### SQL: UPDATE t_withdraw_apply SET last_apply_time=? WHERE user_id = ? AND state = 0

### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

; SQL []; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

很显然,出现死锁的SQL语句是UPDATE t_withdraw_apply SET last_apply_time=? WHERE user_id = ? AND state = 0

再看业务逻辑

int i = withdrawApplyDAO.add(apply);

    if(i == 1) {

      //获取该用户最早的待提现申请时间

      Timestamp earlierTime = withdrawApplyDAO.getEarlierApplyTime(userId);

      withdrawApplyDAO.updateEarlierApplyTime(userId,earlierTime);//更新冗余字段

      //扣除账户余额,然后写入gold_log日志

      int j = userDAO.updateUserGold(0-amount, userId);

......

那么为什么会出现死锁呢?


原来是这样的,用户点击过快同时提交了两次提现申请

那么就会开启两个事务

事务1 插入一条apply

事务2 也插入一条apply

事务1 执行更新 updateEarlierApplyTime ,由于事务2插入的数据也需要更新,所以这个时候 事务1需要等待事务2提交后才能执行

事务2 页执行更新 updateEarlierApplyTime ,同样需要更新事务1插入的输入,也需要等地事务1完成才能继续执行,这样就出现了死锁


怎么解决这个问题呢?

首先出现这个问题的原因是事务1更新的数据包含了事务2插入的数据,事务2更新也包含了事务1插入的数据,那么我们可以让代码改为

 withdrawApplyDAO.updateEarlierApplyTime(userId,earlierTime);//更新冗余字段

 withdrawApplyDAO.add(apply);

这样就能解决死锁问题

其次,出现这样的问题是用户重复提交导致的,所以应该做重复提交的限制,



https://my.oschina.net/u/1244507/blog/479257



猜你喜欢

转载自blog.csdn.net/varyall/article/details/80211144