@Transaction使用注意事项
准备工作:
创建两张mysql表,id设置为自增。test1表有id和name字段,test2有id和name字段(且name字段不为空)
测试一:
controller层
@GetMapping("/test") public Result test(String userName) { return service.test(userName); }
serviceImpl层
@Override @Transactional(rollbackFor = Exception.class) public Result test(String userName) { testMapper.saveTest1("userName1");--没有回滚 try { saveTest2(userName); } catch (Exception e) { log.warn("test报错{}", e.getMessage()); } return Result.succeed("成功"); } @Transactional(rollbackFor = Exception.class) public void saveTest2(String userName) { testMapper.saveTest2(userName);--因为name字段设置了不能为空,所以这条数据没有添加成功 }
mapper层
@Insert("insert into test1(name) values(#{userName})") void saveTest1(String userName); @Insert("insert into test2(name) values(#{userName})") void saveTest2(String userName);
调用/test接口,不传参数,最终结果:
test1表里有两条数据,test2表里没有数据,也就是事务没有回滚。
test1表数据如下
测试二:
controller层
@GetMapping("/test1")
public Result test1(String userName) {
return service.test1(userName);
}
serviceImpl层
@Override
@Transactional(rollbackFor = Exception.class)
public Result test1(String userName) {
testMapper.saveTest1("userName1");
try {
otherServiceImpl.saveTest2(userName); --回滚了
} catch (Exception e) {
log.warn("test报错{}", e.getMessage());
}
return Result.succeed("成功");
}
新建一个otherServiceImpl类,把测试一的saveTest2方法直接挪过来
@Transactional(rollbackFor = Exception.class) public void saveTest2(String userName) { testMapper.saveTest2(userName); --回滚了 }
mapper层
@Insert("insert into test1(name) values(#{userName})")
void saveTest1(String userName);
@Insert("insert into test2(name) values(#{userName})")
void saveTest2(String userName);
调用/test1接口,不传参数,最终结果:
test1和test2表里都没有数据,也就是saveTest2方法被移到另一个service类的时候,代表事务回滚了。
测试一和测试二得出结论:
在同一个类中,一个方法调用另一个带@Transaction注解的方法时,方法上的@Transaction注解不会生效。
解决这个问题,有一个简单的办法,就是新建一个类,将第二个方法移到新写的类里,此时@Transaction注解就可以生效了。
测试三:
controller层
@GetMapping("/test2")
public Result test2(String userName) {
return service.test2(userName);
}
serviceImpl层
@Override @Transactional(rollbackFor = Exception.class) public Result test2(String userName) { testMapper.saveTest1("userName1"); try { saveTest2(userName); } catch (Exception e) { log.warn("test报错{}", e.getMessage()); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return Result.succeed("成功"); } @Transactional(rollbackFor = Exception.class) public void saveTest2(String userName) { testMapper.saveTest2(userName); }
mapper层
@Insert("insert into test1(name) values(#{userName})")
void saveTest1(String userName);
@Insert("insert into test2(name) values(#{userName})")
void saveTest2(String userName);
调用/test3接口,不传参数,最终结果:
test1和test2表里都没有数据。
即:在同一个类中,一个方法调用另一个带@Transaction注解的方法时,加上“TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();”,方法上的@Transaction注解就会生效。