异常日志
### 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);
这样就能解决死锁问题
其次,出现这样的问题是用户重复提交导致的,所以应该做重复提交的限制,