记MySQL事务+消息队列引起的问题

news2025/1/15 20:47:16

问题描述:

先说一下流程:后端保存前端提交的图表信息,然后发送异步消息到消息队列,由下游服务去处理图表信息。

部署项目到服务器,验证项目功能的时候,出现了以下错误:数据库存在数据。下游服务查不到数据库的数据

// service代码
@Override
@Retryable
@Transactional
public ChartVo genChartByAiAsyncMq(Long uid, MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest) {
	// ...省略
	Chart chart = Chart.builder().name(name).goal(goal)
                    .chartData(data).chartType(chartType)
                    .uid(uid).status("wait").build();
     boolean save = this.save(chart);
     if(!save){
         log.info("保存表单失败");
         throw new RuntimeException("保存表单失败");
     }
     List<Chart> list = this.list();
     log.info("chart长度:{}", list.size());
     // 发送消息,触发异步处理
     biMessageProducer.sendMessage(String.valueOf(chart.getId()));
     log.info("发送消息成功");
     // 省略
}
        

下游服务处理代码

@SneakyThrows
@RabbitListener(queues = {MQConstants.BI_QUEUE_NAME}, ackMode = "MANUAL")
public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag){
    log.info("receive message: {}", message);

    // 检查消息是否为空
    if(StringUtils.isBlank(message)){
        log.info("消息不能为空");
        channel.basicNack(deliveryTag, false, false);
        throw new RuntimeException("消息不能为空");
    }
    List<Chart> list = biService.list();
    log.info("图表列表长度:{}", list.size());
    // 尝试将消息解析为图表ID,并查询图表信息
    Long chartId = Long.parseLong(message);
    Chart chart = biService.getById(chartId);
    log.info("图表信息:{}", chart);
    // 图表不存在时的处理
    if(chart == null){
        log.info("图表不存在");
        channel.basicNack(deliveryTag, false, false);
        throw new RuntimeException("图表不存在");
    }
    // 省略
}

日志输出如下:
在这里插入图片描述
数据库信息:
在这里插入图片描述

解决过程

首先说明一下,这个错误之前没有出现过,下午出错,再次测试的时候,也会出现正常的情况,只不过错误占比有点高(10次有6次获取不到数据库消息)。

分析的过程:

步骤1、首先在上游服务和下游服务打印日志,查看数据库有多少条数据,上游服务显示有2条数据,下游服务显示有1条数据
在这里插入图片描述

步骤2、找错的时候,看见方法加了事务注解@Transactional,这个时候想到可能是事务影响(后面分析原因),然后取掉注解,重新验证,发现没有出错
在这里插入图片描述

原因分析

为什么会出现这个错误呢?

我觉得是由MySQL的事务和网络引起的,

MySQL事务+网络

我们都知道MySQL(8.x版本)的事务的隔离级别默认是可重复读(RR),那么一个事务在操作完成之前,对其他事务是不看见的,所以就说,方法中先保存图表信息到数据库,然后发送消息到消息队列,再执行方法的后续过程。发送消息到队列之后,可能数据库事务还没有提交,但是消息发送成功了,就立刻被消费者端消费,此时,消费者端查询数据库中的图表信息,当然查不到,因为生产者端的事务还没有提交。

之前没有出错,这次验证出错分析

服务端将消息发送消息队列,由于网络有延迟,导致事务提交之后,消息才被消费端消费。

解决方法

1、手动提交事务,不使用注解
2、设置延迟队列,但是这个延迟的时间具体是多少,我们无法确定,所以最后采用第一种方法解决此问题。

@Slf4j
@Service
public class BiServiceImpl extends ServiceImpl<ChartMapper, Chart> implements BiService {

	@Resource
	private PlatformTransactionManager transactionManager;
	
	 @Override
	 @Retryable
	 public ChartVo genChartByAiAsyncMq(Long uid, MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest) {
	     TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
	     try{
	        // 省略...
	        Chart chart = Chart.builder().name(name).goal(goal)
                    .chartData(data).chartType(chartType)
                    .uid(uid).status("wait").build();
	         boolean save = this.save(chart);
	         if(!save){
	             log.info("保存表单失败");
	             throw new RuntimeException("保存表单失败");
	         }
	         transactionManager.commit(transactionStatus);
	         List<Chart> list = this.list();
	         log.info("chart长度:{}", list.size());
	         // 发送消息,触发异步处理
	         biMessageProducer.sendMessage(String.valueOf(chart.getId()));
	         log.info("发送消息成功");
	         // 省略...
	     }catch (Exception e){
	         log.error("AI 异步调用失败", e);
	         transactionManager.rollback(transactionStatus);
	         throw new RuntimeException("AI 异步调用失败");
	     }
	
	 }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理 —— 存储系统(DRAM和SRAM,ROM)

计算机组成原理 —— 存储系统&#xff08;DRAM和SRAM&#xff09; DRAM和SRAMDRAM的刷新DRAM地址复用ROM&#xff08;Read-Only Memory&#xff08;只读存储器&#xff09;&#xff09; 我们今天来看DRAM和SRAM&#xff1a; DRAM和SRAM DRAM&#xff08;动态随机存取存储器&…

构建未来应用的核心,云原生技术栈解析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、云原生技术栈 1、容器和容器编排 1.1 Docker 1.2 Kubernete…

JaveEE进阶----Spring Web MVC入门

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、什么是 Spring Web MVC&#xff1f;&#xff1f;1.1MVC 定义1.2 什么是Spring MVC ?1.3过浏览器和用户程序交互 二、 RequestMapping 注解三、Postman 前言…

能理解你的意图的自动化采集工具——AI和爬虫相结合

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

计网:网络应用层【Email应用/SMTP协议】

Email应用与SMTP协议 Email应用层的构成 客户端服务器协议 用户代理 用于读写邮件消息&#xff1b;与服务器交互&#xff0c;收发邮件消息 常见的客户端&#xff1a;Outlook&#xff0c;Foxmail&#xff08;这两个是需要下载的客户端&#xff09;&#xff0c;Web客户端&…

浏览器插件利器-allWebPluginV2.0.0.14-bata版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX插件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持谷歌、火狐等浏…

【数据建模】微分方程与动力系统

文章目录 微分方程与动力系统1. 微分方程的理论基础1.1 函数、导数与微分1.2 一阶线性微分方程的解1.3 二阶常系数线性微分方程的解 2. 使用python求解微分方程2.1 求解微分2.2 求解定积分2.2.1 quad函数求解2.2.2 梯型法则求解 3. 使用Scipy和Sympy解微分方程3.1 使用sympy求解…

4. DSL入门_01

1. 常见的DSL (1) 查询所有: 查询出所有数据&#xff0c;一般测试的时候使用&#xff0c;例如&#xff1a; match_all .但是受分页限制&#xff0c;一般返回10条数据 (2) 全文检索(full text)查询&#xff1a;利用分词器对用户输入内容分词&#xff0c;然后去倒排索引中匹配&a…

三个 insert 导致的死锁问题

锁种类 插入意向锁&#xff08;insert intention lock&#xff09;对已有数据行的修改与删除&#xff0c;必须加强互斥锁 X 锁&#xff0c;那对于数据的插入&#xff0c;是否还需要加这么强的锁&#xff0c;来实施互斥呢&#xff1f;插入意向锁&#xff0c;孕育而生。插入意向…

任务5.2 掌握DStream基础操作

实战&#xff1a;DStream基础操作 了解DStream编程模型&#xff1a;DStream是Spark Streaming中对实时数据流的抽象&#xff0c;可以看作一系列持续的RDD。DStream可以通过外部数据源获取或通过现有DStream的高级操作获得。 操作本质&#xff1a;DStream上的操作最终会转化为对…

OneNote for Windows 10 下载

OneNote for Windows 10 安装 1.在浏览器中输入地址&#xff1a;https://apps.microsoft.com/detail/9wzdncrfhvjl?hlzh-cn&glUS2OneNote for Windows 10 - 在 Windows 上免费下载并安装 |Microsoft StoreOneNote 是用于在设备上捕获和组织你的一切内容的数字笔记本。快速…

对日期的处理

对日期的处理 对编码进行统一&#xff0c;在脚本最开始&#xff1a; # -*- coding: utf-8 -*-这里涉及到两个操作&#xff0c;一个是将数据进行标准化&#xff0c;比如有些日期是2024/05/06这并不符合日期的标准格式&#xff0c;需要转换成这样的2024-05-06 def tran_std(st…

八爪鱼现金流-030,升级日志

八爪鱼现金流 八爪鱼 2024年4月4日09:27:02 v-0.0.1 资产包、负债包&#xff0c;功能优化 2024年4月15日09:27:26 v-0.0.2 增加公告模块 2024年4月18日12:14:32 v-0.0.3 市场查询优化。创建人脱敏处理。增加市场风云菜单。 2024年4月18日15:57:10 v-0.0.4 对于无截止日…

[MYSQL] 数据库基础

1.什么是数据库 从数据库的名字可以看出,它是用来操作(增删查改....)数据的,事实上也的确如此,通过数据库,我们可以更方便.更高效的来操作.管理数据 以文件形式存储数据的缺点 文件的安全问题文件不利于数据的查询和删除文件不利于存储海量数据操作文件并不方便 为了解决上述问…

【Vue-Vben-Admin】1、初次运行和介绍

【Vue-Vben-Admin】1、初次运行和介绍 Vben-Admin 初次运行和介绍 小小的介绍规定版本文件树安装依赖运行项目 小小的介绍 一款 Vue3 Typescript4 Vite2 后台管理项目&#xff0c;功能挺多的&#xff0c;还有组件库 规定版本 此个人文档规定版本为 2.8.0&#xff0c;可能版本…

消息队列MQ相关面试题

消息队列MQ相关面试题 1 RabbitMQ 1.1 你们项目中哪里用到了RabbitMQ ? 难易程度&#xff1a;☆☆☆ 出现频率&#xff1a;☆☆☆☆ 我们项目中很多地方都使用了RabbitMQ , RabbitMQ 是我们项目中服务通信的主要方式之一 , 我们项目中服务通信主要有二种方式实现 : 通过Fei…

STM32 温湿度采集与OLED显示

目录 一、I2C总线通信协议 1、I2C介绍 2、软件I2C和硬件I2C &#xff08;1&#xff09;硬件I2C &#xff08;2&#xff09;软件I2C 差异 二、AHT20温湿度传感器 接口原理介绍 1. 温度测量原理 2. 湿度测量原理 实物引脚 传感器性能 电气特性 三、任务实现 具…

【python】美妆类商品跨境电商数据分析(源码+课程论文+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-37微调

37微调 import os import torch import torchvision from torch import nn import liliPytorch as lp import matplotlib.pyplot as plt from d2l import torch as d2l# 获取数据集 d2l.DATA_HUB[hotdog] (d2l.DATA_URL hotdog.zip,fba480ffa8aa7e0febbb511d181409f899b9baa5…

setInterval 定时任务执行时间不准验证

一般在处理定时任务的时候都使用setInterval间隔定时调用任务。 setInterval(() > {console.log("interval"); }, 2 * 1000);我们定义的是两秒执行一次&#xff0c;但是浏览器实际执行的间隔时间只多不少。这是由于浏览器执行 JS 是单线程模式&#xff0c;使用se…