【Spring事务】Spring事务事件控制,解决业务异步操作
使用背景
在业务中,经常会有这样的需求,在数据库事务提交之后,发送异步消息或者进行其他的事务操作。
例如当用户注册成功之后,发送激活码,如果用户注册后就执行发送激活码,但是在用户保存时出现提交事务异常,数据库进行回滚,用户实际没有注册成功,但是用户却收到了激活码,此时,正确的是应该在用户注册保存事务提交完成之后,然后发送激活码。
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
使用注解@TransactionalEventListener
demo展示
事务监听器
@Component
public class TransactionListener {@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)public void handler(TransactionEvent transactionEvent) {System.out.println(transactionEvent.getSource());}
}
业务代码
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void saveUser() {User user = new User();userMapper.insert(user);eventPublisher.publishEvent(newTransactionEvent("事务提交后发布事件1"));
}
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
源码解析
EventListenerMethodProcessor
EventListenerMethodProcessor
用来解析带有带有@EventListener
注解的方法。遍历类上的方法,判断工厂是否支持,用对应的工厂生成监听器。
private void processBean(final String beanName, final Class<?> targetType) {if (!this.nonAnnotatedClasses.contains(targetType) &&AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&!isSpringContainerClass(targetType)) {//...if (CollectionUtils.isEmpty(annotatedMethods)) {//...}else {// Non-empty set of methodsConfigurableApplicationContext context = this.applicationContext;Assert.state(context != null, "No ApplicationContext set");List<EventListenerFactory> factories = this.eventListenerFactories;Assert.state(factories != null, "EventListenerFactory List not initialized");for (Method method : annotatedMethods.keySet()) {for (EventListenerFactory factory : factories) {if (factory.supportsMethod(method)) {Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));ApplicationListener<?> applicationListener =factory.createApplicationListener(beanName, targetType, methodToUse);if (applicationListener instanceof ApplicationListenerMethodAdapter) {((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);}context.addApplicationListener(applicationListener);break;}}}if (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +beanName + "': " + annotatedMethods);}}}}
TransactionalEventListenerFactory
仅支持TransactionalEventListener
注解,生成ApplicationListenerMethodTransactionalAdapter
的对象。
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {private int order = 50;public TransactionalEventListenerFactory() {}public void setOrder(int order) {this.order = order;}public int getOrder() {return this.order;}public boolean supportsMethod(Method method) {return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);}public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);}
}
在AbstractTransactionManagementConfiguration
会引入TransactionalEventListenerFactory
。
@Bean(name = {"org.springframework.transaction.config.internalTransactionalEventListenerFactory"})@Role(2)public static TransactionalEventListenerFactory transactionalEventListenerFactory() {return new TransactionalEventListenerFactory();}
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
ApplicationListenerMethodTransactionalAdapter
发布事件,主要是创建了TransactionSynchronization
,注册到了TransactionSynchronizationManager
public void onApplicationEvent(ApplicationEvent event) {if (TransactionSynchronizationManager.isSynchronizationActive() && TransactionSynchronizationManager.isActualTransactionActive()) {TransactionSynchronization transactionSynchronization = this.createTransactionSynchronization(event);TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);} else if (this.annotation.fallbackExecution()) {if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && this.logger.isWarnEnabled()) {this.logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");}this.processEvent(event);} else if (this.logger.isDebugEnabled()) {this.logger.debug("No transaction is active - skipping " + event);}}
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
事务提交
TransactionSynchronizationUtils#invokeAfterCompletion
,事务提交会遍历TransactionSynchronization
执行afterCompletion
方法
public static void invokeAfterCompletion(@Nullable List<TransactionSynchronization> synchronizations, int completionStatus) {if (synchronizations != null) {Iterator var2 = synchronizations.iterator();while(var2.hasNext()) {TransactionSynchronization synchronization = (TransactionSynchronization)var2.next();try {synchronization.afterCompletion(completionStatus);} catch (Throwable var5) {logger.error("TransactionSynchronization.afterCompletion threw exception", var5);}}}
ApplicationListenerMethodTransactionalAdapter.TransactionSynchronizationEventAdapter#afterCompletion
,调用事件监听器的processEvent
方法,会反射调用被@TransactionalEventListener
修饰的方法。
public void afterCompletion(int status) {if (this.phase == TransactionPhase.AFTER_COMMIT && status == 0) {this.processEvent();} else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == 1) {this.processEvent();} else if (this.phase == TransactionPhase.AFTER_COMPLETION) {this.processEvent();}}protected void processEvent() {this.listener.processEvent(this.event);}
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
使用TransactionSynchronizationManager
和 TransactionSynchronizationAdapter
demo展示
@Autowired
private UserDao userDao;
@Autowired
private JmsProducer jmsProducer;public User saveUser(User user) {// 保存用户userDao.save(user);final int userId = user.getId();// 兼容无论是否有事务if(TransactionSynchronizationManager.isActualTransactionActive()) {TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {jmsProducer.sendEmail(userId);}});} else {jmsProducer.sendEmail(userId);}
}
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
标题复制10行,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作【Spring事务】Spring事务事件控制,解决业务异步操作,并且每行大于10个字符【Spring事务】Spring事务事件控制,解决业务异步操作
相关文章:

【Spring事务】Spring事务事件控制,解决业务异步操作
使用背景 在业务中,经常会有这样的需求,在数据库事务提交之后,发送异步消息或者进行其他的事务操作。 例如当用户注册成功之后,发送激活码,如果用户注册后就执行发送激活码,但是在用户保存时出现提交事务…...
Java 中的注释有哪些?
在 Java 中,有三种注释方式:单行注释、多行注释和文档注释。注释是程序中的一种重要的辅助性说明文字,可以增加程序的可读性和可维护性,方便其他程序员阅读和理解代码。 单行注释 单行注释是指以“//”开头的注释,注释…...

yolov4
1 V4版本概述 集各种优秀方案于一身,嫁接了众多主流的目标识别方面的情况。 V4 贡献 3. 数据增强策略分析 BOF Bag of freebies(BOF) Mosiac 数据增强 Mixup 比如将狗和猫的两张图片混合,一半猫,一半狗。 label 也变成 Dog 0.5 , Cat 0…...

金融学第二版笔记第一章1.1
第1部分 金融和金融体系 第一章金融学 1.1 一、 对金融学进行界定 1.金融 金融是货币流通、信用活动及与之相关的经济行为的总称。 简言之,就是货币资金的融通。一般是指以银行、证券市场等为中心的货币流通和信用调节活动,包括货币的发行和流通、存…...

[架构之路-193]-《软考-系统分析师》-2-应用数学 - 项目周期与关键路径(PERT图、甘特图、单代号网络图、双代号网络图)
1. 关键概念 1.1 关键路径 关键路径通常(但并非总是)是决定项目工期的进度活动序列。它是项目中最长的路径,即使很小浮动也可能直接影响整个项目的最早完成时间。关键路径的工期决定了整个项目的工期,任何关键路径上的终端元素…...

滋灌中小企业,分销伙伴和华为来做“送水人”
最近有个段子:第一批靠生成式AI赚大钱的人,既不是研发人员,也不是国内大厂,而是卖课的。 大家笑谈,每一轮新技术的掘金之路,最先致富的都是送水、卖铲子的。 这其实隐藏了一个信息技术产业的普遍规律&#…...

面试华为测试岗,收到offer后我却毫不犹豫拒绝了....
我大学学的是计算机专业,毕业的时候,对于找工作比较迷茫,也不知道当时怎么想的,一头就扎进了一家外包公司,一干就是2年。我想说的是,但凡有点机会,千万别去外包! 在深思熟虑过后&am…...
深入了解浮点型变量输入与输出
深入了解浮点型变量输入与输出 前言 C 语言中浮点型变量的输入和输出在程序开发中非常常见,比如经常出现在数据处理和科学计算中。在此篇文章中,我们将探讨浮点型变量输入和输出的一些细节和注意事项。 浮点型变量的定义和初始化 在 C 语言中&#x…...

Vector - CAPL - CANoe硬件配置函数 - 03
目录 canFlushTxQueue -- 刷新已定义的Tx队列 代码示例 canSetChannelAcc -- CANoe接收过滤器设置 代码示例 canSetChannelMode -- CAN控制器Tx使能/失能 代码示例 canSetChannelOutput -- Ack自应答使能/失能 代码示例 getCardTypeEx -- CAN控制器类型 canFlushTxQue…...

单开网页应用利器 - BroadcastChannel
前言 前段时间在做一个基于 psd 模板生成图片的应用,其中重要的功能就是打开编辑器页面来设计出图。但是有个问题,每当我点击一个模板,就会新开一个浏览器页签。现代浏览器是以空间换时间的运行思路来提高效率,这就导致了内存开销…...

OpenCv更改颜色空间以及图像阈值
本文主要讲解以下几个方面: 如何将图片从一个颜色空间转换到另一个,例如 BGR 到 Gray,BGR 到 HSV 等。简单阈值法另外,我们会创建一个从图片中提取彩色对象的应用。 1.改变颜色空间 cv.cvtColor(img, flag) 参数flag表示颜色空间转换的方…...
(邱维声)高等代数课程笔记:基,维数与坐标
3.5 基,维数与坐标 \quad 本节,继续研究线性空间的结构。一般地,设 V V V 是数域 K K K 上的一个线性空间。 \quad 首先,我们先将“线性相关”与“线性无关”的概念由“有限”向“无限”推广。 对比其它高等代数教程,…...

Spring Security + Jwt 集成实现登录
文章目录 前言Maven 相关依赖配置文件自定义springsecurity相关认证流程继承WebSecurityConfigurerAdapter继承AbstractAuthenticationToken继承AbstractAuthenticationProcessingFilter实现AuthenticationProvider实现UserDetailsService实现AccessDeniedHandler实现Authentic…...

yolov5 用自己的数据集进行训练
在训练之前先要按照一定目录格式准备数据: VOC标签格式转yolo格式并划分训练集和测试集_爱钓鱼的歪猴的博客-CSDN博客 目录 1、修改数据配置文件 2、修改模型配置文件 3、训练 1、修改数据配置文件 coco.yaml 拷贝data/scripts/coco.yaml文件, pa…...

1951-2023最新中国基础地理信息,包括水系、行政区、DEM高程、气象站经纬位置、土地利用,这些数据获取方法介绍
水系: 流域内所有河流、湖泊等各种水体组成的水网系统,称作水系。其中,水流最终流入海洋的称作外流水系,如太平洋水系、北冰洋水系;水流最终流入内陆湖泊或消失于荒漠之中的,称作内流水系。 [1] 流域面积的…...
CAD处理控件Aspose.CAD功能演示:在 C#中以编程方式搜索 DWG 图形文件中的文本
Aspose.CAD 是一个独立的类库,以加强 Java应用程序处理和渲染CAD图纸,而不需要AutoCAD或任何其他渲染工作流程。该CAD类库允许将DWG, DWT, DWF, DWFX, IFC, PLT, DGN, OB…...

实验二十、压控电压源二阶 LPF 幅频特性的研究
一、题目 研究压控电压源二阶低通滤波电路品质因数 Q Q Q 对频率特性的影响。 二、仿真电路 电路如图1所示。集成运放采用 LM324AJ,其电源电压为 15V。 图 1 压控电压源二阶低通滤波电路幅频特性的测试 图1\,\,压控电压源二阶低通滤波电路幅频特性的测试 图1压控…...

类和对象【C++】【中篇】
目录 一、类的6个默认成员函数 1、构造函数 2、析构函数 3、拷贝构造函数 4、赋值重载函数 二、赋值运算符重载 一、类的6个默认成员函数 注意:默认成员函数不能在类外面定义成全局函数。因为类里没有的话会自动生成,就会产生冲突。 1、构造函数…...

2.SpringBoot运维实用篇
SpringBoot运维实用篇 基础篇发布以后,看到了很多小伙伴在网上的留言,也帮助超过100位小伙伴解决了一些遇到的问题,并且已经发现了部分问题具有典型性,预计将有些问题在后面篇章的合适位置添加到本套课程中,作为解…...
【c++】浅讲引用
【c】浅讲引用 前言引用定义作用做输出型参数引用作返回值总结 关于引用的权限 结尾 前言 博主开始细学c和linux了 这次就带来浅学了的引用。 引用 定义 引用不是在内存中开辟一个新空间的新变量 类似于给变量取别名,和取别名的对象在空间中公用一个对象 例&#…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...