java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot中的事务

SpringBoot中的事务全方位详解

作者:Pluto372

这篇文章主要介绍了SpringBoot中的事务全方位详解,在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理两种方式,文中举例详细说明了这两种事务,需要的朋友可以参考下

SpringBoot事务的基本介绍

事务管理方式

在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理两种方式。

编程式事务管理:

1、使用 TransactionTemplate 来管理事务:

@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                try {
                    // ....  业务代码
                } catch (Exception e){
                    //回滚
                    transactionStatus.setRollbackOnly();
                }
            }
        });
}

2、使用 TransactionManager 来管理事务:

@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction() {
  TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
          try {
               // ....  业务代码
              transactionManager.commit(status);
          } catch (Exception e) {
              transactionManager.rollback(status);
          }
}

声明式事务管理:

  @Transactional
    public void testTransactional(){
    }

事务提交方式

默认情况下,数据库处于自动提交模式。

每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。

对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。

不过,这个我们不用担心,spring会将底层连接的自动提交特性设置为false。

也就是在使用spring进行事物管理的时候,spring会将是否自动提交设置为false,等价于JDBC中的 connection.setAutoCommit(false);,在执行完之后在进行提交,connection.commit(); 。

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

事务传播行为

当事务方法被另外一个事务方法调用时,必须指定事务应该如何传播,例如,方法可能继续在当前事务中执行,也可以开启一个新的事务,在自己的事务中执行。

也就是说如果a方法和b方法都添加了注解,在默认传播模式下,a方法内部调用b方法,会把两个方法的事务合并为一个事务。

事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。

spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。

可以明确的配置在抛出那些异常时回滚事务,包括checked异常。

也可以明确定义那些异常抛出时不回滚事务。

事务常用配置

@Transaction失效场景

1、访问权限问题 (只有public方法会生效)

java的访问权限主要有四种:private、default、protected、public,它们的权限从左到右,依次变大。spring要求被代理方法必须得是public的。

我们自定义的事务方法如果它的访问权限不是public,会导致事务失效。

 	@Transactional
    private void testTransactional() {
    }

2、方法用final修饰,不会生效

有时候,某个方法不想被子类重新,这时可以将该方法定义成final的。

普通方法这样定义是没问题的,但如果将事务方法定义成final,会导致事务失效

 	@Transactional
    public final void testTransactional() {
    }

3、同一个类中的方法直接内部调用,会导致事务失效

@Service
public class TransactionalTest implements TransactionalService{
    @Override
    public  void testTransactional() {
        transactional();
    }
    @Transactional
    public  void  transactional(){}
}

文章开头说道,声明式事务管理是建立在AOP之上的。AOP的实现原理是动态代理。

一个方法调用本类的其他方法是不会走代理,原因是在InvocationHandlerImpl#invoke中method.invoke(subject, args);

这里调用的是目标类subject的方法,直接执行目标类方法,不会执行代理类的方法。​

因为JDK动态代理采用的是接口实现的方式,通过反射调用目标类的方法,此时如果调用本类的方法,this指的是目标类,并不是代理类所以不会走代理。

不走代理,事务自然会失效。

编写新的sevice

这个方法非常简单,只需要新加一个Service方法,把@Transactional注解加到新Service方法上,把需要事务执行的代码移到新方法中。

自己注入自己

@Service
public class TransactionalTest implements TransactionalService{
    @Resource
   private TransactionalTest transactionalTest;
    @Override
    public  void testTransactional() {
        transactionalTest.transactional();
    }
    @Transactional
    public  void  transactional(){}
}

如果不想再新加一个Service类,在该Service类中注入自己。

完全不用担心循环依赖的问题,spring ioc内部的三级缓存保证了它,不会出现循环依赖问题。

4、事务方法中使用try-catch捕获处理

   @Transactional
    public  void  transactional(){
        try{
        ....
        }catch(Exception e){
            logger.error("",e);
        }
    }

事务@Transactional由spring控制时,它会在抛出异常的时候进行回滚。如果自己使用try-catch捕获处理了,是不生效的。

如果想事务生效可以进行手动回滚或者在catch里面将异常抛出【throw new RuntimeException();】

事务手动回滚

  try{
      ...
  }catch(Exception e){
      log.error("fail",e);
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      return false;
  }

回滚部分异常 使用【Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 】设置回滚点。

使用【TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);】回滚到savePoint。

@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){  
    success();  
    //只回滚以下异常,
    Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
    try {  
        exception(); 
     } catch (Exception e) {  
        e.printStackTrace();     
        // 手工回滚事务
        TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
        return response.error();
     }  
    return response.success();
}

到此这篇关于SpringBoot中的事务全方位详解的文章就介绍到这了,更多相关SpringBoot中的事务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文