Spring Mybatis 事务死锁解决全过程

使用的事务管理是

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);
}

 这样一来,经过测试,不再出现锁超时的情况了。

但是总感觉,这样的异步控制是不应该在业务代码中进行控制的!

 

猜你喜欢

转载自l810102251.iteye.com/blog/2323251