使用的事务管理是
org.springframework.jdbc.datasource.DataSourceTransactionManager
一、刚开始事务是这样实现的
TransactionStatus ts = transactionManager.getTransaction(null); try { // 得到用户信息 User user = userMapper.selectByPrimaryKey(userId); user.setHealthBeans(user.getHealthBeans() == null ? 0 : user.getHealthBeans()); Article article = articleMapper.selectByPrimaryKey(articleId); User createrUser = userMapper.selectByPrimaryKey(article.getCreater()); HealthBeansRecord record = new HealthBeansRecord(); healthBeansRecordMapper.insertSelective(record); record.setNumber((byte) +exceptionalCount); healthBeansRecordMapper.insertSelective(record); userMapper.modifyHealthBeans(userId, -exceptionalCount); userMapper.modifyHealthBeans(createrUser.getId(), exceptionalCount); transactionManager.commit(ts); } catch (Exception e) { transactionManager.rollback(ts); throw new BasicException(String.format("出现异常,异常原因:%s,参数userId:%s,参数articleId:%s", e.getMessage(), userId, articleId), e); }
但是会时不时的出现:
### Error updating database. Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction ### The error may involve defaultParameterMap ### The error occurred while setting parameters
二、改成如下方式
扫描二维码关注公众号,回复:
583183 查看本文章
try { ts = transactionManager.getTransaction(null); // 得到用户信息 User user = userMapper.selectByPrimaryKey(userId); user.setHealthBeans(user.getHealthBeans() == null ? 0 : user.getHealthBeans()); Article article = articleMapper.selectByPrimaryKey(articleId); User createrUser = userMapper.selectByPrimaryKey(article.getCreater()); HealthBeansRecord record = new HealthBeansRecord(); healthBeansRecordMapper.insertSelective(record); record.setUserId(createrUser.getId()); record.setNumber((byte) +exceptionalCount); healthBeansRecordMapper.insertSelective(record); userMapper.modifyHealthBeans(userId, -exceptionalCount); userMapper.modifyHealthBeans(createrUser.getId(), exceptionalCount); transactionManager.commit(ts); } catch (Exception e) { transactionManager.rollback(ts); throw new BasicException(String.format("出现异常,异常原因:%s,参数userId:%s,参数articleId:%s", e.getMessage(), userId, articleId), e); }
将TransactionStatus的声明为类的成员变量,在try catch中完成事务的使用。这样锁超时的错误少了很多,但是还会出现超时的情况
三、给使用事务的代码添加类级异步锁
try { synchronized (getClass()) { ts = transactionManager.getTransaction(null); // 得到用户信息 User user = userMapper.selectByPrimaryKey(userId); user.setHealthBeans(user.getHealthBeans() == null ? 0 : user.getHealthBeans()); Article article = articleMapper.selectByPrimaryKey(articleId); User createrUser = userMapper.selectByPrimaryKey(article.getCreater()); HealthBeansRecord record = new HealthBeansRecord(); healthBeansRecordMapper.insertSelective(record); record.setUserId(createrUser.getId()); record.setNumber((byte) +exceptionalCount); healthBeansRecordMapper.insertSelective(record); userMapper.modifyHealthBeans(userId, -exceptionalCount); userMapper.modifyHealthBeans(createrUser.getId(), exceptionalCount); transactionManager.commit(ts); } } catch (Exception e) { transactionManager.rollback(ts); throw new BasicException(String.format("出现异常,异常原因:%s,参数userId:%s,参数articleId:%s", e.getMessage(), userId, articleId), e); }
这样一来,经过测试,不再出现锁超时的情况了。
但是总感觉,这样的异步控制是不应该在业务代码中进行控制的!