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

「事务一致性」事务afterCommit

在事务还没有执行完消息就已经发出去了, 导致后续的一些数据或逻辑上的问题产生。

场景如下:

  • 异步-记录日志:当事务提交后,再记录日志。

  • 发送mq消息:只有业务数据都存入表后,再发mq消息。

方案1. 利用TransactionSynchronizationManager的registerSynchronization()方法注册TransactionSynchronization实现类

我们只需要在执行的事务方法中, 添加如下代码, 就可以完成在事务提交后的逻辑处理了

// TransactionSynchronizationAdapter是TransactionSynchronization的默认实现
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {// 事务提交后需要执行的业务逻辑: 发消息, 日志...}
});

原理:

Spring 事务的扩展 – TransactionSynchronization

事务操作的时候它的当前线程还保存了 TransactionSynchronization 对象。而这个对象伴随着 Spring 对 事务处理的各个生命周期都会有相应的扩展

public interface TransactionSynchronization extends Flushable {/** 事务提交状态 */int STATUS_COMMITTED = 0;/** 事务回滚状态 */int STATUS_ROLLED_BACK = 1;/**系统异常状态 */int STATUS_UNKNOWN = 2;void suspend();void resume();void flush();// 事务提交之前void beforeCommit(boolean readOnly);// 事务成功或者事务回滚之前void beforeCompletion();// 事务成功提交之后void afterCommit();// 操作完成之后(包含事务成功或者事务回滚)void afterCompletion(int status);}

事务的事务扩展项目中的应用场景是当订单成功之后,发送一条消息到 MQ 当中去。由于事务是和数据库连接相绑定的,如果把发送消息和数据库操作放在一个事务里面。当发送消息时间过长时会占用数据库连接,所以就要把数据库操作与发送消息到 MQ 解耦开来。可以利用 TransactionSynchronization#afterCommit 的这个方法,当数据成功保存到数据库并且事务提交了就把消息发送到 MQ 里面。

@Transactional
public void finishOrder(Order order){// 修改订单成功updateOrderSuccess(order);// 发送消息到 MQTransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){@Overridepublic void afterCommit() {mqService.send(order);}});
}

当事务成功提交之后,就会把消息发送给 MQ,并且不会占用数据库连接资源。

方式二、Spring 事务扩展 – @TransactionalEventListener

在 Spring framework 4.2 之后还可以使用@TransactionalEventListener处理数据库事务提交成功后再执行操作。这种方式比 TransactionSynchronization 更加优雅。它的使用方式如下:

@Autowired
private ApplicationEventPublisher publisher;@Override
@Transactional(rollbackFor = Exception.class)
public void add(AdvanceChargeApplyAddInput input) {this.save(advanceChargeApply);// 发送事件publisher.publishEvent(advanceChargeApply);
}
// 响应事件, 事务提交后执行
@TransactionalEventListener
public void handle(PayloadApplicationEvent<AdvanceChargeApply> event) {System.out.println("TransactionalEventListener 事务提交后执行");
}

也可以自定义事件源和事件监听:

     @Transactionalpublic void finishOrder(Order order){// 修改订单成功updateOrderSuccess(order);// 发布 Spring Event 事件applicationEventPublisher.publishEvent(new MyAfterTransactionEvent(order));}@Slf4j@Componentprivate static class MyTransactionListener {@Autowiredprivate MqService mqService;@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)private void onHelloEvent(MyAfterTransactionEvent event) {Order order = event.getOrder();mqService.send(order);}}// 定一个事件,继承自ApplicationEvent private static class MyAfterTransactionEvent extends ApplicationEvent {private Order order;public MyAfterTransactionEvent(Object source, Order order) {super(source);this.order = order;}public Order getOrder() {return order;}}

它的实现原理是当 Spring Bean 的方法标注了通过 TransactionalEventListenerFactory#createApplicationListener创建 ApplicationListenerMethodTransactionalAdapter 然后在事件回调当中创建 TransactionSynchronization的实现类TransactionSynchronizationEventAdapter。并且通过 TransactionSynchronizationManager.registerSynchronization

把 TransactionSynchronizationEventAdapter 注册到当前线程当中。

TransactionSynchronizationEventAdapter
     private static class TransactionSynchronizationEventAdapter extends TransactionSynchronizationAdapter {private final ApplicationListenerMethodAdapter listener;private final ApplicationEvent event;private final TransactionPhase phase;public TransactionSynchronizationEventAdapter(ApplicationListenerMethodAdapter listener,ApplicationEvent event, TransactionPhase phase) {this.listener = listener;this.event = event;this.phase = phase;}@Overridepublic int getOrder() {return this.listener.getOrder();}@Overridepublic void beforeCommit(boolean readOnly) {if (this.phase == TransactionPhase.BEFORE_COMMIT) {processEvent();}}@Overridepublic void afterCompletion(int status) {if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) {processEvent();}else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) {processEvent();}else if (this.phase == TransactionPhase.AFTER_COMPLETION) {processEvent();}}protected void processEvent() {this.listener.processEvent(this.event);}}

相关文章:

「事务一致性」事务afterCommit

在事务还没有执行完消息就已经发出去了, 导致后续的一些数据或逻辑上的问题产生。场景如下&#xff1a;异步-记录日志&#xff1a;当事务提交后&#xff0c;再记录日志。发送mq消息&#xff1a;只有业务数据都存入表后&#xff0c;再发mq消息。方案1. 利用TransactionSynchroni…...

【深度学习编译器系列】2. 深度学习编译器的通用设计架构

在【深度学习编译器系列】1. 为什么需要深度学习编译器&#xff1f;中我们了解到了为什么需要深度学习编译器&#xff0c;和什么是深度学习编译器&#xff0c;接下来我们把深度学习编译器这个小黑盒打开&#xff0c;看看里面有什么东西。 1. 深度学习编译器的通用设计架构 与…...

图解操作系统

硬件结构 CPU是如何执行程序的&#xff1f; 图灵机的工作方式 图灵机的基本思想&#xff1a;用机器来模拟人们用纸笔进行数学运算的过程&#xff0c;还定义了由计算机的那些部分组成&#xff0c;程序又是如何执行的。 图灵机的基本组成如下&#xff1a; 有一条「纸带」&am…...

【发版或上线项目保姆级心得】

第一步&#xff1a;先在正式环境创建数据库/新增表格或者字段 在数据库表中增加字段/表格&#xff0c;不会报错。 但是切记不要过早数据库字段/表格或者删除字段/表格 第二步&#xff1a;修改配置文件 先将正式环境需要的配置给写好&#xff0c;包括但不仅限于数据库配置、…...

Python数据分析-pandas库入门

pandas 库概述pandas 提供了快速便捷处理结构化数据的大量数据结构和函数。自从2010年出现以来&#xff0c;它助使 Python 成为强大而高效的数据分析环境。pandas使用最多的数据结构对象是 DataFrame&#xff0c;它是一个面向列&#xff08;column-oriented&#xff09;的二维表…...

MacBook Pro 恢复出厂设置

目录1.恢复出厂设置1.1 按Command-R 键1.2 macOS 实用工具1.3 从 macOS 恢复功能的实用工具窗口中选择“磁盘工具”&#xff0c;然后点按“继续”1.4 在“磁盘工具”边栏中选择您的设备或宗卷。1.5 点按“抹掉”按钮或标签页1.6 抹掉OS X HD - 数据 完成1.7 抹掉 OS X HD1.8 查…...

googletest 笔记

什么是一个好的测试 1 测试应该是独立的和可重复的。调试一个由于其他测试而成功或 失败的测试是一件痛苦的事情。googletest 通过在不同的对象上 运行测试来隔离测试。当测试失败时&#xff0c;googletest 允许您单独运 行它以快速调试。 2 测试应该很好地“组织”&#xff0c…...

MySQL修改密码的几种方式?

第一种方式&#xff1a; 最简单的方法就是借助第三方工具Navicat for MySQL来修改。方法如下&#xff1a; 1、登录mysql到指定库&#xff0c;如&#xff1a;登录到test库。 2、然后点击上方"用户"按钮。 3、选择要更改的用户名&#xff0c;然后点击上方的"编辑用…...

关于画一个句号--基于2022年终总结的反思与分享

没有平台鼓风造势&#xff0c;今年各大平台没有涌现出一批总结&#xff0c;非常清爽 正如同人发明了抽屉&#xff0c;将杂物进行整理、丢弃、收纳&#xff0c;才能对空间进行更合理地使用。我们也需要对知识、过往经历进行整理、丢弃、收纳&#xff0c;才能对大脑进行更合理地…...

学习Flask之三、模板

学习Flask之三、模板 书写易于维护的应用的关键是书写整洁和良构的代码。到目前为止你所见的例子过于简单而不能体现这点。把两个目的完全独立的Flask view 函数当作一个来写&#xff0c;会产生问题。view函数的一个显然的任务是对请求作出响应&#xff0c;如前面的例子所示。对…...

2023-02-20干活小计:

所以我今天的活开始了&#xff1a; In this paper, the authors target the problem of Multimodal Name Entity Recognition(MNER) as an improvement on NER(text only) The paper proposes a multimodal fusion based on a heterogeneous graph of texts and images to mak…...

LeetCode_动态规划_困难_1326.灌溉花园的最少水龙头数目

目录1.题目2.思路3.代码实现&#xff08;Java&#xff09;1.题目 在 x 轴上有一个一维的花园。花园长度为 n&#xff0c;从点 0 开始&#xff0c;到点 n 结束。 花园里总共有 n 1 个水龙头&#xff0c;分别位于 [0, 1, …, n] 。 给你一个整数 n 和一个长度为 n 1 的整数数…...

mac tcpdump学习

学习原因 工作上遇到了重启wifi后无法发出mDNS packet的情况&#xff0c;琢磨一下用tcpdump用的命令如下 sudo tcpdump -n -k -s 0 -i en0 -w VENDOR-DUT-INTERFACE.pcapng是在测airplay BCT认证时&#xff0c;官方文档的解决方法。对tcpdump很不了解&#xff0c;现汇总如下的学…...

【跟我一起读《视觉惯性SLAM理论与源码解析》】第二章 编程及编译工具

23.2.21终于拿到六哥的新书 感觉很是不错&#xff0c;打算近期写一写心得之类的 废话不多说&#xff0c;直接开啃 PS&#xff1a;我的建议是阅读完十四讲后再来看这本书&#xff0c;效果应该会很不错。 因为第一章都是介绍之类的我觉得没什么整理的必要&#xff0c;所以直接来…...

广东望京卡牌科技有限公司,2023年团建活动圆满举行

玉兔初临&#xff0c;春天相随&#xff0c;抖擞精神&#xff0c;好运连连。春天是一个万物复苏的季节&#xff0c;来自广东的望京卡牌科技有限公司&#xff0c;也迎来了新年第一次团建活动。在“乘风破浪、追逐梦想”的口号声中&#xff0c;2023望京卡牌目标启动会团结活动正式…...

ts语法如何在Vue3中运用?

一、父子传值的用法 父传子&#xff1a;defineProps的TS写法 // 父组件&#xff1a;和 vue2 一样正常传值 <template><div class"login-page"><cp-nav-bar title"登录" right-text"注册"></cp-nav-bar></div> &…...

RK3566添加湿度传感器以及浅析hal层

RK3566添加一款温湿度传感器gxht3x.挂在i2c总线下。驱动部分就不多做解析。大致流程硬件接好i2c线以及vcc gnd。后看数据手册。初始化寄存器&#xff0c;然后要读数据的话读那个寄存器&#xff0c;读出来的数据要做一个转化,然后实现open read write ioctl函数就行了。本文主要…...

看了这份Java高级笔试宝典覆盖近3年Java笔试中98%高频知识点,反打面试官

首先声明&#xff1a; 本书覆盖了近3年程序员面试笔试中超过98%Java高频知识点&#xff0c;当你细细品读完本书后&#xff0c;面试都是小问题。 一书在手/工作不愁 记住重点&#xff0c;考试要考 前言 程序员求职始终是当前社会的一个热点&#xff0c;而市面上有很多关于程…...

从0到1搭建大数据平台之监控

大家好&#xff0c;我是脚丫先生 (o^^o) 大数据平台设计中&#xff0c;监控系统尤为重要。 它时刻关乎大数据开发人员的幸福感。 试想如果半夜三更&#xff0c;被电话吵醒解决集群故障问题&#xff0c;那是多么的痛苦&#xff01;&#xff01;&#xff01; 但是不加班是不可…...

采购评标管理过程是怎样的?有哪些评标标准?

采购活动的评标是检查和比较投标的有组织的过程&#xff0c;以选择最佳报价&#xff0c;努力获得实现企业目标所需的货物、工程和服务。 评标是由一个被称为评标小组的机构负责。这个小组如何称呼&#xff0c;取决于企业的情况。同义词有报价审查小组、投标审查委员会或投标审…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...