当前位置: 首页 > news >正文

【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事务事件控制,解决业务异步操作

使用背景 在业务中&#xff0c;经常会有这样的需求&#xff0c;在数据库事务提交之后&#xff0c;发送异步消息或者进行其他的事务操作。 例如当用户注册成功之后&#xff0c;发送激活码&#xff0c;如果用户注册后就执行发送激活码&#xff0c;但是在用户保存时出现提交事务…...

Java 中的注释有哪些?

在 Java 中&#xff0c;有三种注释方式&#xff1a;单行注释、多行注释和文档注释。注释是程序中的一种重要的辅助性说明文字&#xff0c;可以增加程序的可读性和可维护性&#xff0c;方便其他程序员阅读和理解代码。 单行注释 单行注释是指以“//”开头的注释&#xff0c;注释…...

yolov4

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

金融学第二版笔记第一章1.1

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

[架构之路-193]-《软考-系统分析师》-2-应用数学 - 项目周期与关键路径(PERT图、甘特图、单代号网络图、双代号网络图)

1. 关键概念 1.1 关键路径 关键路径通常&#xff08;但并非总是&#xff09;是决定项目工期的进度活动序列。它是项目中最长的路径&#xff0c;即使很小浮动也可能直接影响整个项目的最早完成时间。关键路径的工期决定了整个项目的工期&#xff0c;任何关键路径上的终端元素…...

滋灌中小企业,分销伙伴和华为来做“送水人”

最近有个段子&#xff1a;第一批靠生成式AI赚大钱的人&#xff0c;既不是研发人员&#xff0c;也不是国内大厂&#xff0c;而是卖课的。 大家笑谈&#xff0c;每一轮新技术的掘金之路&#xff0c;最先致富的都是送水、卖铲子的。 这其实隐藏了一个信息技术产业的普遍规律&#…...

面试华为测试岗,收到offer后我却毫不犹豫拒绝了....

我大学学的是计算机专业&#xff0c;毕业的时候&#xff0c;对于找工作比较迷茫&#xff0c;也不知道当时怎么想的&#xff0c;一头就扎进了一家外包公司&#xff0c;一干就是2年。我想说的是&#xff0c;但凡有点机会&#xff0c;千万别去外包&#xff01; 在深思熟虑过后&am…...

深入了解浮点型变量输入与输出

深入了解浮点型变量输入与输出 前言 C 语言中浮点型变量的输入和输出在程序开发中非常常见&#xff0c;比如经常出现在数据处理和科学计算中。在此篇文章中&#xff0c;我们将探讨浮点型变量输入和输出的一些细节和注意事项。 浮点型变量的定义和初始化 在 C 语言中&#x…...

Vector - CAPL - CANoe硬件配置函数 - 03

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

单开网页应用利器 - BroadcastChannel

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

OpenCv更改颜色空间以及图像阈值

本文主要讲解以下几个方面: 如何将图片从一个颜色空间转换到另一个&#xff0c;例如 BGR 到 Gray&#xff0c;BGR 到 HSV 等。简单阈值法另外&#xff0c;我们会创建一个从图片中提取彩色对象的应用。 1.改变颜色空间 cv.cvtColor(img, flag) 参数flag表示颜色空间转换的方…...

(邱维声)高等代数课程笔记:基,维数与坐标

3.5 基&#xff0c;维数与坐标 \quad 本节&#xff0c;继续研究线性空间的结构。一般地&#xff0c;设 V V V 是数域 K K K 上的一个线性空间。 \quad 首先&#xff0c;我们先将“线性相关”与“线性无关”的概念由“有限”向“无限”推广。 对比其它高等代数教程&#xff0c…...

Spring Security + Jwt 集成实现登录

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

yolov5 用自己的数据集进行训练

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

1951-2023最新中国基础地理信息,包括水系、行政区、DEM高程、气象站经纬位置、土地利用,这些数据获取方法介绍

水系&#xff1a; 流域内所有河流、湖泊等各种水体组成的水网系统&#xff0c;称作水系。其中&#xff0c;水流最终流入海洋的称作外流水系&#xff0c;如太平洋水系、北冰洋水系&#xff1b;水流最终流入内陆湖泊或消失于荒漠之中的&#xff0c;称作内流水系。 [1] 流域面积的…...

CAD处理控件Aspose.CAD功能演示:在 C#中以编程方式搜索 DWG 图形文件中的文本

Aspose.CAD 是一个独立的类库&#xff0c;以加强 Java应用程序处理和渲染CAD图纸&#xff0c;而不需要AutoCAD或任何其他渲染工作流程。该CAD类库允许将DWG&#xff0c; DWT&#xff0c; DWF&#xff0c; DWFX&#xff0c; IFC&#xff0c; PLT&#xff0c; DGN&#xff0c; OB…...

实验二十、压控电压源二阶 LPF 幅频特性的研究

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

类和对象【C++】【中篇】

目录 一、类的6个默认成员函数 1、构造函数 2、析构函数 3、拷贝构造函数 4、赋值重载函数 二、赋值运算符重载 一、类的6个默认成员函数 注意&#xff1a;默认成员函数不能在类外面定义成全局函数。因为类里没有的话会自动生成&#xff0c;就会产生冲突。 1、构造函数…...

2.SpringBoot运维实用篇

SpringBoot运维实用篇 ​ 基础篇发布以后&#xff0c;看到了很多小伙伴在网上的留言&#xff0c;也帮助超过100位小伙伴解决了一些遇到的问题&#xff0c;并且已经发现了部分问题具有典型性&#xff0c;预计将有些问题在后面篇章的合适位置添加到本套课程中&#xff0c;作为解…...

【c++】浅讲引用

【c】浅讲引用 前言引用定义作用做输出型参数引用作返回值总结 关于引用的权限 结尾 前言 博主开始细学c和linux了 这次就带来浅学了的引用。 引用 定义 引用不是在内存中开辟一个新空间的新变量 类似于给变量取别名&#xff0c;和取别名的对象在空间中公用一个对象 例&#…...

使用VSCode开发Django指南

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

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

华为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 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

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

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

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

基于SpringBoot在线拍卖系统的设计和实现

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