首页 > 编程知识 正文

springboot事务传播机制,spring事务传播机制应用场景

时间:2023-05-06 15:37:13 阅读:242658 作者:1798

一、序言

Spring中声明式事务确实给我们带来了很大的便利,在Service层方法上带上@Transactional注解即可实现事务,首先看看@Transactional的默认配置:

1、默认使用的事务管理器名字为"transactionManager"。

2、默认事务隔离传播为Propagation.REQUIRED。

3、默认超时时长为底层事务系统的时长。

4、默认事务隔离级别为数据库的隔离级别。

5、默认事务类型为读写事务。

6、默认发生RuntimeExeption异常会触发事务回滚,而受检异常不会。

@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};} 二、事务传播机制介绍 public enum Propagation { /** * 如果当前线程执行的方法如果没有事务则创建新事务,否则在已存在事务中执行 * / REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED), /** * 如果当前线程执行的方法如果有事务,则在事务中执行,否则无事务执行 * / SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS), /** * 当前线程执行的方法必须有事务,否则抛出异常 * /MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY), /** * 当前线程执行方法每次都会创建新的事务,如果当前方法已在事务中执行,则会挂起外部事务 * /REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), /** * 当前线程所执行的方法在无事务环境中执行,如果已有外部事务,则会挂起外部事务 * /NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), /** * 当前线程所执行的方法在无事务环境中执行,如果已有外部事务,则会抛出异常 * /NEVER(TransactionDefinition.PROPAGATION_NEVER), /** * 如果外部事务存在,则当前线程所在方法会在嵌套事务中执行。 * 如果外部事务不存在,则和REQUIRED效果一样。 * /NESTED(TransactionDefinition.PROPAGATION_NESTED);} 三、嵌套事务实例 1、Propagation.REQUIRED @Servicepublic class TransactionServiceB { @Autowired private OperationLogMapper operationLogMapper; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void methodB() { OperationLogDo operationLog = new OperationLogDo(); operationLog.setOpType(1); operationLog.setOpContent("新增操作"); operationLog.setUserId(1); operationLog.setCreateTime(new Date()); operationLogMapper.saveOperationLog(operationLog); }}@Servicepublic class TransactionServiceA { @Autowired private TransactionServiceB serviceB; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void methodA() { serviceB.methodB(); throw new RuntimeException("发生异常了!"); }}

由于methodA和methodB事务的传播机制都是Propagation.REQUIRED,因此methodB会和methodA在同一个事务中执行,当methodA执行发生异常时,methodB会回滚,因此methodB中的插入操作不会生效。

2、Propagation.REQUIRES_NEW @Servicepublic class TransactionServiceA { @Autowired private TransactionServiceB serviceB; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void methodA() { serviceB.methodB(); throw new RuntimeException("发生异常了!"); }}@Servicepublic class TransactionServiceB { @Autowired private OperationLogMapper operationLogMapper; @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public void methodB() { OperationLogDo operationLog = new OperationLogDo(); operationLog.setOpType(1); operationLog.setOpContent("新增操作"); operationLog.setUserId(1); operationLog.setCreateTime(new Date()); operationLogMapper.saveOperationLog(operationLog); }}

methodA方法上的事务传播机制是Propagation.REQUIRED,而methodB方法上的事务传播机制Propagation.REQUIRES_NEW,因此methodB方法会在一个新的事务中执行,同时外部事务(即methodA所在事务)会被挂起。这里我们看到的效果是数据库中仍然插入了一条记录,说明不受外部事务影响。

3、Propagation.NESTED @Servicepublic class TransactionServiceA { @Autowired private OperationLogMapper operationLogMapper; @Autowired private TransactionServiceB serviceB; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void methodA() { serviceB.methodB(); OperationLogDo operationLog = new OperationLogDo(); operationLog.setOpType(1); operationLog.setOpContent("修改操作"); operationLog.setUserId(1); operationLog.setCreateTime(new Date()); operationLogMapper.saveOperationLog(operationLog); throw new RuntimeException("发生异常了!"); }}@Servicepublic class TransactionServiceB { @Autowired private OperationLogMapper operationLogMapper; @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class) public void methodB() { OperationLogDo operationLog = new OperationLogDo(); operationLog.setOpType(1); operationLog.setOpContent("新增操作"); operationLog.setUserId(1); operationLog.setCreateTime(new Date()); operationLogMapper.saveOperationLog(operationLog); }}

此时methodA方法在methodB方法执行完后抛出了异常,最后的结果是methodB中的插入操作回滚了。为什么呢?我们可以把嵌套事务看做是外部事务的一个子事务,既然外部事务发生异常回滚了,那么子事务也会回滚,但要注意子事务不会影响外部事务。而如果methodB上的隔离级别设为REQUIRES_NEW,那么methodB中的插入操作会生效,因为methodB方法执行会在一个新的事务环境中,不受其它事务影响。

有同学会发现,上面的例子即使methodB方法上的事务传播机制为Propagation.REQUIRED,methodB方法中的插入操作也会回滚,那我们再看看Propagation.NESTED和Propagation.REQUIRED的区别,下面再进行改写:

@Servicepublic class TransactionServiceA { @Autowired private OperationLogMapper operationLogMapper; @Autowired private TransactionServiceB serviceB; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void methodA() { try { serviceB.methodB(); } catch (Exception e) { e.printStackTrace(); } OperationLogDo operationLog = new OperationLogDo(); operationLog.setOpType(1); operationLog.setOpContent("修改操作"); operationLog.setUserId(1); operationLog.setCreateTime(new Date()); operationLogMapper.saveOperationLog(operationLog); }}@Servicepublic class TransactionServiceB { @Autowired private OperationLogMapper operationLogMapper; @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class) public void methodB() { OperationLogDo operationLog = new OperationLogDo(); operationLog.setOpType(1); operationLog.setOpContent("新增操作"); operationLog.setUserId(1); operationLog.setCreateTime(new Date()); operationLogMapper.saveOperationLog(operationLog); throw new RuntimeException("发生异常了!"); }}

上面这个例子看到的效果是methodB方法中的插入操作会回滚,而methodA方法在捕获methodB方法抛出的异常后执行插入操作,因此数据库会新增一条记录。这也说明当methodB方法的传播机制为Propagation.NESTED时,methodB方法所在的事务为外部事务的一个子事务,子事务不会影响外部事务。当然如果methodA方法不捕获异常,那么methodA方法中的插入操作同样也会回滚。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。