最近开发的版本测试说线上经常报错,错误日志看来下是提示事务时间超时了,原因就是在执行sql之前进行了很长时间的算法调用和文件处理,注释掉 @Transactional 注解就不会在报错了,但是这样会出现脏数据,所以需要跳过前面的处理逻辑,只在sql执行的这段代码处理事务。
先写一个demo验证下,以下就是没加事务然后出现了脏数据,主要加上@Transactional注解就可以解决,但是@Transactional是让整个方法都包在了这个事务里面,粒度不够细,所以需要用到 transactionTemplate。
首先注入 TransactionTemplate ,然后调用execute方法,需要new一个TransactionCallback并且重写doInTransaction方法,然后在里面实现逻辑。
@Autowired
private TransactionTemplate transactionTemplate;
/**
* 代码级别的事务控制
*/
// @Transactional
@Test
public void transactionTemplateTest(){
transactionTemplate.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus transactionStatus) {
for (int i = 0; i < 10; i++) {
Item item = new Item();
item.setName("数据"+i);
if (i == 5)throw new RuntimeException();
itemMapper.insert(item);
}
return Boolean.TRUE;
}
});
}
测试2
public void transactionTemplateTest(){
//设置超时时间,单位秒,execute 执行的时间如果超过设置时间就会提示事务超时
// transactionTemplate.setTimeout(20);
/**
* 这句插入没有在事务的控制范围内,即使下的插入出现了异常也已经入库了
*/
Item item = new Item();
item.setName("数据"+0);
itemMapper.insert(item);
// 核心代码,实现TransactionCallback 的 doInTransaction 接口操作数据库
transactionTemplate.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus transactionStatus) {
for (int i = 1; i < 10; i++) {
Item item = new Item();
item.setName("数据"+1);
if (i == 5) throw new RuntimeException();
itemMapper.insert(item);
}
return Boolean.TRUE;
}
});
}
查看数据库,数据0插入了,但是下面插入的几条数据因为出现异常回滚了。