springBootservice层事务控制的操作
springBoot使⽤事物⽐较简单,在Application启动类s上添加@EnableTransactionManagement注解,然后在service层的⽅法上添加@Transactional注解
@Transactional属性
属性类型描述
value String可选的限定描述符,指定使⽤的事务管理器propagation enum: Propagation可选的事务传播⾏为设置
isolation enum: Isolation可选的事务隔离级别设置
readOnly boolean读写或只读事务,默认读写
timeout int (in seconds granularity)事务超时时间设置
rollbackFor Class对象数组,必须继承⾃Throwable导致事务回滚的异常类数组rollbackForClassName类名数组,必须继承⾃Throwable导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承⾃Throwable不会导致事务回滚的异常类数组noRollbackForClassName类名数组,必须继承⾃Throwable不会导致事务回滚的异常类名字数组
⽤法:
@Transactional 可以作⽤于接⼝、接⼝⽅法、类以及类⽅法上。当作⽤于类上时,该类的所有 public ⽅法将都具有该类型的事务属性,同时,我们也可以在⽅法级别使⽤该标注来覆盖类级别的定义。
虽然 @Transactional 注解可以作⽤于接⼝、接⼝⽅法、类以及类⽅法上,但是 Spring 建议不要在接⼝或者接⼝⽅法上使⽤该注解,因为这只有在使⽤基于接⼝的代理时它才会⽣效。
另外, @Transactional 注解应该只被应⽤到 public ⽅法上,这是由 Spring AOP 的本质决定的。
如果你在 protected、private 或者默认可见性的⽅法上使⽤ @Transactional 注解,这将被忽略,也不会抛出任何异常。
默认情况下,只有来⾃外部的⽅法调⽤才会被AOP代理捕获,也就是,类内部⽅法调⽤本类内部的其他⽅法并不会引起事务⾏为,即使被调⽤⽅法使⽤@Transactional注解进⾏修饰。
注解在⽅法上:
@Autowired
springboot原理图解private MyBatisDao dao;
@Transactional
@Override
public void insert(Test test) {
dao.insert(test);
throw new RuntimeException("test");//抛出unchecked异常,触发事物,回滚
}
@Transactional(noRollbackFor=RuntimeException.class)
@Override
public void insert(Test test) {
dao.insert(test);
//抛出unchecked异常,触发事物,noRollbackFor=RuntimeException.class,不回滚
throw new RuntimeException("test");
}
@Transactional(propagation=Propagation.NOT_SUPPORTED)
@Override
public void insert(Test test) {
//事物传播⾏为是PROPAGATION_NOT_SUPPORTED,以⾮事务⽅式运⾏,不会存⼊数据库
dao.insert(test);
}
注解在类上:当作⽤于类上时,该类的所有 public ⽅法将都具有该类型的事务属性
@Transactional
public class MyBatisServiceImpl implements MyBatisService {
@Autowired
private MyBatisDao dao;
@Override
public void insert(Test test) {
dao.insert(test);
//抛出unchecked异常,触发事物,回滚
throw new RuntimeException("test");
}
注意:有时候在开发时往往出现了添加注解后却⽆法回滚
原因:默认spring事务只在发⽣未被捕获的 RuntimeException 时才回滚。
spring aop 异常捕获原理:被拦截的⽅法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到⽅法的异常,才能进⾏回滚,默认情况下aop只捕获 RuntimeException 的异常,但可以通过配置来捕获特定的异常并回滚
换句话说在service的⽅法中不使⽤try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进⽽回滚。
解决⽅案:
1.在service层⽅法抛出RuntimeException异常(如在Catch中需要抛出⾃定义的异常则只需⾃定义异常继承RuntimeException 即可),并继续捕获和处理这个异常。
2.在service层⽅法的catch语句中增加:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
语句,⼿动回滚,这样上层就⽆需去处理异常。
补充:springboot多个service互相调⽤的事务处理
今天,想在⼀个service的⽅法A中,调⽤另⼀个service的⽅法B,⽅法A和⽅法B均存在数据库插⼊操作,并且@Transaction 注解也都加了,但是当B⽅法中抛出异常时,A中的插⼊语句还是能够执⾏成功。
注解配置如下:
@Transactional(isolation= Isolation.DEFAULT,propagation= Propagation.REQUIRED)
百思不得其解,再查了相关资料后,问题还是出在@Transaction注解的配置上,需要配置异常回滚。
@Transactional(isolation= Isolation.DEFAULT,propagation= Propagation.REQUIRED,rollbackFor = Exception.class)
这样,当B⽅法中抛出异常时,A中的操作也会进⾏回滚,事务就会起到控制作⽤。
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。如有错误或未考虑完全的地⽅,望不吝赐教。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论