深入理解Spring事务传播机制-原理与实例说明

事务传播机制

简化记忆版本

  1. REQUIRED:有事务加入,没有事务创建,Spring默认
  2. MANDATORY:必须在事务中被调用,没有抛异常
  3. SUPPORTS:有事务加入,没有以非事务运行
  4. NOT_SUPPORTED:不需要事务,有事务则挂起,避免回滚。例如记日志,避免日志信息回滚
  5. REQUIRES_NEW:当前方法创建新事务运行,如果有事务则挂起,主要是为了控制敏感资源事务粒度,避免从时间锁,可以局部回滚
  6. NESTED:如果有事务,加入事务但是记录保存点,如果没有事务创建事务,主要作用局部回滚(通过savepoint实现),不挂起已有事务
  7. NEVER:该方法不应该在事务中运行,如果存在事务则抛异常

不同传播机制之间的区别

REQUIRED与MANDATORY:REQUIRED没有事务自己创建,MANDATOR没有事务异常。

传播机制区别
REQUIRED与MANDATORY方法没有事务,REQUIRED自己创建;而MANDATOR抛出异常
REQUIRED与REQUIRES_NEW方法在事务中执行,REQUIRED加入该事务;REQUIRES_NEW会挂起已有的事务,创建自己的事务
NESTED与REQUIRES_NEW方法在事务中执行NESTED加入该事务,并记录回滚点;REQUIRES_NEW挂起已有事务,创建新事务
NESTED与REQUIRED都是有事务加入,没有事务创建,但NESTED比REQUIRED多了保存回滚点
NOT_SUPPORTED与NEVER方法在事务中被调用NOT_SUPPORTED会挂起事务,而NEVER会抛出异常
MANDATORY与NEVER两者相反, 没有在事务中MANDATORY抛出异常,而有事务NEVER抛出异常
SUPPORTS与没有传播机制注解感觉没有区别,发现有区别的朋友可以补充一下

当SUPPORTS方法被NEVER、NOT_SUPPORTED、没有@Transactional注解这些方法调用,不会有事务,和不加注解效果一样。
当SUPPORTS方法被REQUIRED、MANDATORY、REQUIRES_NEW、NESTED这些方法调用时,加入事务,和不加注解效果也一样。

所以SUPPORTS应用场景是啥?

问题测试

REQUIRED与MANDATORY

@Service
public class ServiceA
{@Transactional(propagation = Propagation.REQUIRED)public void methodA(){methodB();}@Transactional(propagation = Propagation.MANDATORY)public void methodB(){}
}@Service
public class ServiceC
{@Resourceprivate ServiceA serviceA;public void methodC(){// 创建一个事务执行方法AserviceA.methodA();// methodB是MANDATORY,但是methodC没有事务,所以直接抛出异常serviceA.methodB();}
}

NESTED回滚测试

@Service
public class ServiceA
{@Transactional(propagation = Propagation.NESTED)public void methodA(){// 数据库操作TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}@Service
public class ServiceB
{@Transactional(propagation = Propagation.NESTED)public void methodB(){// 数据库操作}
}@Service
public class ServiceC
{@Resourceprivate ServiceA serviceA;@Resourceprivate ServiceB serviceB;@Transactionalpublic void methodC(){serviceA.methodA();serviceB.methodB();}
}

上面的操作哪些会回滚?

答案是:
methodA会回滚
methodB不回滚

因为methodA、methodB是NESTED,记录了回滚点,所以只有methodA被回滚。

NESTED传播测试

做一点小变动,如果把methodA上的@Transactional(propagation = Propagation.NESTED)注解去掉呢?
放在methodC方法上会怎样?

@Service
public class ServiceA
{public void methodA(){// 数据库操作TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}@Service
public class ServiceB
{@Transactional(propagation = Propagation.NESTED)public void methodB(){// 数据库操作}
}@Service
public class ServiceC
{@Resourceprivate ServiceA serviceA;@Resourceprivate ServiceB serviceB;@Transactional(propagation = Propagation.NESTED)public void methodC(){serviceA.methodA();serviceB.methodB();}
}

答案是:
methodA会回滚
methodB会回滚

因为methodA没有注解,就相当于使用的是methodC的事务,并且所以回滚点在methodC,
methodB也使用了methodC的事务,也设置了回滚点,但是在methodA中回滚,整个事务都回滚了。

如何只回滚methodB,不回滚methodA呢?

答案是:
将methodA的TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()放在方法放methodB中就可以。
当methodB是NESTED的时候,在其中回滚,因为有回滚点,所以只会回滚methodB中操作,不会影响methodC方法。

REQUIRES_NEW回滚测试

再来一点点小变动:
将methodB的NESTED换为REQUIRES_NEW会怎样?

@Service
public class ServiceA
{public void methodA(){// 数据库操作TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}@Service
public class ServiceB
{@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB(){// 数据库操作}
}@Service
public class ServiceC
{@Resourceprivate ServiceA serviceA;@Resourceprivate ServiceB serviceB;@Transactional(propagation = Propagation.NESTED)public void methodC(){serviceA.methodA();serviceB.methodB();}
}

答案是:
methodA会回滚
methodB不回滚

把methodB的NESTED换为REQUIRES_NEW就可以,因为REQUIRES_NEW为挂起原有事务,并创建新的事务,
所以methodC的事务不会影响到methodB的事务。

异常对不同传播机制回滚影响测试

再来一点点小变动:

将methodA中的手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
换为:throw new RuntimeException(“我要异常”);

会怎样呢?

@Service
public class ServiceA
{@Transactional(propagation = Propagation.NESTED)public void methodA(){// 数据库操作throw new RuntimeException("我要异常");}
}@Service
public class ServiceB
{@Transactional(propagation = Propagation.NESTED)public void methodB(){// 数据库操作}
}@Service
public class ServiceC
{@Resourceprivate ServiceA serviceA;@Resourceprivate ServiceB serviceB;@Transactionalpublic void methodC(){serviceA.methodA();serviceB.methodB();}
}

答案是:
methodA会回滚
methodB会回滚

如果异常这一次把methodB的传播机制换NESTED为REQUIRES_NEW还能生效吗?

答案是:不能。

很难理解?

的确比较绕,其实很简单,因为异常了,根本就没有执行到methodB,就直接回滚了。

事务内部调用

再来点简单点的问题。

// 调用 1
public class ServiceA
{@Transactionalpublic void methodA(){userMapper.insertSelective(UserTO.builder().username("tim").email("test@gmail.com").build());methodB();}public void methodB(){eventLogMapper.insertSelective(EventLogTO.builder().type((short) 1).message("创建用户").build());}
}

这个事务会生效吗?

答案是:会,很简单,在方法methodA中调用methodB,其实和把methodB的方法体放入methodA方法体中没有什么一样。

在这里插入图片描述

// 调用2
public class ServiceA
{public void methodA(){methodB();}@Transactionalpublic void methodB(){}
}

这个事务会生效吗?

答案是:不能,很多朋友都知道,因为没有走代理,Spring的事务必须通过代理。

如何让它生效呢?

不要直接调用,通过Spring的方式来呗。

@EnableAspectJAutoProxy(exposeProxy = true)
ServiceA serviceA = (ServiceA)AopContext.currentProxy();
serviceA.methodB();

或者:

@Resource
private ApplicationContext applicationContext;
ServiceA serviceA = applicationContext.getBean(this.getClass());
serviceA.methodB();

或者:

@Service
public class ServiceA
{@Resourceprivate ServiceB serviceB;public void methodA(){serviceB.methodB();}
}@Service
public class ServiceB
{    @Transactionalpublic void methodB(){}
}

SQL

CREATE TABLE user (id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',username varchar(30) DEFAULT NULL COMMENT '姓名',age smallint(5) unsigned DEFAULT NULL COMMENT '年龄',sex tinyint DEFAULT -1 COMMENT '性别(-1-保密,1-男,2-女)',email varchar(255) DEFAULT NULL COMMENT '邮箱',status tinyint DEFAULT 1 COMMENT '状态(-1-删除,1-正常)' ,create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';CREATE TABLE event_log (id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',message varchar(255) DEFAULT NULL COMMENT '信息',type smallint(5) unsigned DEFAULT NULL COMMENT '事件类型',create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='事件日志';

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/28150.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黑马头条 分布式任务调度 定时计算热点文章、xxl-job、kafkaStream

xxl-Job分布式任务调度 1 今日内容 1.1 需求分析 目前实现的思路:从数据库直接按照发布时间倒序查询 问题1: 如何访问量较大,直接查询数据库,压力较大问题2: 新发布的文章会展示在前面,并不是热点文章 1.2 …

## 流体力学或湍流理论中壁函数(wall function)

流体力学或湍流理论中壁函数(wall function) 一、壁函数(wall function)概念 在流体力学或湍流理论中,壁函数是基于壁定律得到的无量纲速度 u u^ u与无量纲壁距 y y^ y之间的函数关系。 在对数层区域,速…

WooCommerce适合企业电子商务吗?

目录 成功开展电子商务业务变得比以往任何时候都容易。市场上有几个现成的平台,完全有可能将一个初步的想法快速转变为在线贸易业务,并源源不断地收到订单。 什么是 WooCommerce? 为什么您应该考虑使用 WooCommerce 很灵活 重量轻且功…

Sentinel 规则详解

Sentinel 规则 流控规则 flow1、QPS流控2、并发线程数流控3、流控模式4、流控效果 熔断(降级)规则 degrade1、慢调用比例2、异常比例3、异常数 热点规则 param-flow授权规则 authority1、应用场景2、自定义来源3、授权规则配置 系统规则 前言&#xff1a…

GitLab 私有 Go Modules 的搭建配置

配置步骤 配置 GitLab Access Token 将 GitLab Access Token 写入到 ~/.netrc 文件里(也就是根目录下的 .netrc 文件),没有则新建,并写入内容:machine git.tenorshare.cn login ${USER_NAME} password ${GITLAB_ACCESS_TOKEN},其中 ${USER_NAME} 是GitLab 用户名,${GIT…

【Java基础教程】(十八)包及访问权限篇 · 下:Java编程中的权限控制修饰符、单例设计模式 (Singleton)和多例设计模式的综合探析~

Java基础教程之包及访问权限 下 本节学习目标1️⃣ 访问控制权限2️⃣ 命名规范3️⃣ 单例设计模式 (Singleton)4️⃣ 多例设计模式 本节学习目标 掌握Java 中的4种访问权限;掌握Java 语言的命名规范;掌握单例设计模式与多例设计模式的定义结构&#x…

Java处理doc类型的Word文档转换成html(按顺序保留格式+图片)

最新有个新需求,就是doc文档转换html内容倒不是很难,给大家分享一下,总体思路就是按doc转html的思路来走,唯一缺点是不会自动转换图片,图片是要手动转成base64,默认是有html、body、head、meta等等标签&…

2023四大进销存软件推荐,第一款适合中小商户使用!

在当今竞争激烈的商业环境中,企业或商户迫切需要使用进销存管理软件,来优化库存控制、提高运营效率、降低成本,并加强与供应链合作伙伴之间的协作和沟通。 为了帮助企业选择适合自己需求的进销存软件,我们特别整理了2023年市面上比…

【Java虚拟机学习1】JVM运行时数据区

JVM运行时数据区 一、前言 我们知道Java程序是运行在JVM(Java虚拟机)上的,Java程序运行时会占用一定的内存,在虚拟机自动管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,不容易出现…

第一次用用Opencv进行图像处理

2023.7.06更新 codeblocks安装opencv 直接放参考链接,完成安装该步骤来,简单高效! 安装教程链接 有一个问题就是第一次安装完成后运行时会报确实某些ddl的错误,关机重启就好啦! 尝试运行 ddl的错误解决后可以用以…

行业追踪,2023-07-18,减速器,汽车零部件是重点关注板块,随时开启

自动复盘 2023-07-18 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…

异步复位同步释放

1、概念 异步复位同步释放就是在复位信号到来的时候不受时钟信号的同步,在复位信号释放的时候受到时钟信号的同步; 优点是可以避免电路出现瞬态错误或者亚稳态。 2、原理图 3、代码实现 /***********************************************/ /**…