Spring Mybatis 事务死锁解决全过程
程序员文章站
2022-06-16 16:52:59
...
使用的事务管理是
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
二、改成如下方式
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); }
这样一来,经过测试,不再出现锁超时的情况了。
但是总感觉,这样的异步控制是不应该在业务代码中进行控制的!
上一篇: 吃火锅要什么配菜,火锅这样吃才叫美味
推荐阅读
-
Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
-
Spring事务失效问题分析及解决方案
-
Spring和Mybatis整合全过程实现(idea实现)适合初学spring和mybatis
-
解决spring结合mybatis时一级缓存失效的问题
-
解决Spring或SpringBoot开启事务以后无法返回自增主键的问题
-
spring事务深入剖析 - 事务框架和mybatis如何衔接的
-
SPRING ,HIBERNATE,MYBATIS重构系统(带spring事务测试及spring Restful测试)
-
SPRING ,HIBERNATE,MYBATIS重构系统(带spring事务测试及spring Restful测试)
-
Spring MVC @Transactional注解方式事务失效的解决办法
-
spring+mybatis+atomikos 实现JTA事务