关于Seata的一个小issue...


文章目录

  • 引言
  • 原因🤓
  • 解决方法😵
  • 总结❤️


引言

某一天,笔者在逛着Github的时候,突然看到seata有个有趣的issue,是一个task。

相关描述:

While running the DruidSQLRecognizerFactoryTest.testIsSqlSyntaxSupports test, a ParserException is thrown when attempting to parse a SQL statement that starts with REPLACE. This indicates that the Druid SQL parser does not support the REPLACE SQL syntax.

简单来说,就是issue主人在做另一个pr的时候,发现DruidSQLRecognizerFactoryTest测试类的方法testIsSqlSyntaxSupports,当解析REPLACE语句的时候,会抛出ParserException。这会导致某个模块的maven构建失败,所以他希望有人可以解决这个问题。

原因🤓

笔者研究了一下,这是因为底层的Druid SQL解析器本来就不支持解析相关的REPLACE语法,而相关测试类的处理方法则是抛出异常并打印相关日志,并没有处理该异常或者转换该异常

异常堆栈:

com.alibaba.druid.sql.parser.ParserException: not supported.pos 7, line 1, column 1, token REPLACEat com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:616)at com.alibaba.druid.sql.SQLUtils.parseStatements(SQLUtils.java:603)at org.apache.seata.sqlparser.druid.DruidSQLRecognizerFactoryImpl.create(DruidSQLRecognizerFactoryImpl.java:41)at org.apache.seata.sqlparser.druid.DruidSQLRecognizerFactoryTest.testIsSqlSyntaxSupports(DruidSQLRecognizerFactoryTest.java:172)

解决方法😵

在 Seata 中将 Druid 抛出的 ParserException 转换为 Seata 自定义异常

这样做的好处是:

  1. 异常处理统一 - 所有不支持的SQL语法都抛出 NotSupportYetException

  2. 测试逻辑一致 - 所有数据库类型使用相同的测试断言

  3. 兼容性保持 - DruidIsolationTest 等其他测试正常运行

  4. 用户体验改善 - 提供统一、友好的错误信息

最终,GitHub Action构建成功 - 不再因为stderr输出而失败

但是,你以为这样就结束了吗?不会!!!

修改一个类往往会有蝴蝶效应。

笔者在修改之后进行maven构建时,发现测试类依然报错,但是明明笔者已经测试过了该类的测试类是否正确运行,那为什么还会有测试类报错呢?答案是因为修改了DruidSQLRecognizerFactoryImpl,而maven构建检查的时候,其他测试类也会一起运行,所以修改的类不能将全部异常都抛出是NotSupportYetException,对只是ParserException才进行转换抛出NotSupportYetException

具体修改:

1.在DruidSQLRecognizerFactoryImpl新建立一个私有方法,用来确定是否是ParserException,如果是,才转换抛出NotSupportYetException,否则按原有异常抛出

2.只对会抛出ParserException的方法进行try-catch,避免用一个大的try-catch来包裹住整个方法,提高可读性

3.将asts等名字转换成sqlStatements,提高可读性

4.使用反射方式检查异常类型,避免直接引用 ParserException(因为ParserException 的直接引用导致类加载时的依赖问题。例如在 DruidIsolationTest 中,类隔离机制会阻止某些Druid类的加载,包括 ParserException)

修改的源码如下:

/*** DruidSQLRecognizerFactoryImpl**/
class DruidSQLRecognizerFactoryImpl implements SQLRecognizerFactory {@Overridepublic List<SQLRecognizer> create(String sql, String dbType) {List<SQLStatement> sqlStatements;try {sqlStatements = SQLUtils.parseStatements(sql, DruidDbTypeAdapter.getAdaptiveDbType(dbType));} catch (RuntimeException e) {if (isParserException(e)) {throw new NotSupportYetException("not support the sql syntax: " + sql + "\nplease see the doc about SQL restrictions https://seata.apache.org/zh-cn/docs/user/sqlreference/dml", e);}throw e;}if (CollectionUtils.isEmpty(sqlStatements)) {throw new UnsupportedOperationException("Unsupported SQL: " + sql);}if (sqlStatements.size() > 1 && !(sqlStatements.stream().allMatch(statement -> statement instanceof SQLUpdateStatement)|| sqlStatements.stream().allMatch(statement -> statement instanceof SQLDeleteStatement))) {throw new UnsupportedOperationException("ONLY SUPPORT SAME TYPE (UPDATE OR DELETE) MULTI SQL -" + sql);}List<SQLRecognizer> recognizers = null;SQLRecognizer recognizer = null;for (SQLStatement sqlStatement : sqlStatements) {SQLOperateRecognizerHolder recognizerHolder =SQLOperateRecognizerHolderFactory.getSQLRecognizerHolder(dbType.toLowerCase());if (sqlStatement instanceof SQLInsertStatement) {recognizer = recognizerHolder.getInsertRecognizer(sql, sqlStatement);} else if (sqlStatement instanceof SQLUpdateStatement) {recognizer = recognizerHolder.getUpdateRecognizer(sql, sqlStatement);} else if (sqlStatement instanceof SQLDeleteStatement) {recognizer = recognizerHolder.getDeleteRecognizer(sql, sqlStatement);} else if (sqlStatement instanceof SQLSelectStatement) {recognizer = recognizerHolder.getSelectForUpdateRecognizer(sql, sqlStatement);}if (sqlStatement instanceof SQLReplaceStatement) {throw new NotSupportYetException("not support the sql syntax with ReplaceStatement:" + sqlStatement +"\nplease see the doc about SQL restrictions https://seata.apache.org/zh-cn/docs/user/sqlreference/dml");}if (recognizer != null && recognizer.isSqlSyntaxSupports()) {if (recognizers == null) {recognizers = new ArrayList<>();}recognizers.add(recognizer);}}return recognizers;}/*** Check if the exception is a Druid ParserException* Use class name comparison to avoid directly referencing the ParserException class*/private boolean isParserException(Throwable e) {if (e == null) {return false;}String className = e.getClass().getName();return "com.alibaba.druid.sql.parser.ParserException".equals(className);}
}

总结❤️

如果你看了这篇文章有收获可以点赞+关注+收藏🤩,这是对笔者更新的最大鼓励!如果你有更多方案或者文章中有错漏之处,请在评论区提出帮助笔者勘误,祝你拿到更好的offer!

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

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

相关文章

FTTR+软路由网络拓扑方案

文章目录 网络拓扑软路由配置FTTR光猫路由器TPLink路由器配置WAN设置LAN设置 参考 网络拓扑 软路由配置 配置静态IP地址&#xff1a;192.168.1.100设置网关指向主路由的IP 设置自定义DNS服务器 开启DHCP 这一步很关键&#xff0c;可以让连上wifi的所有设备自动趴强。 FTTR光猫…

RPC - 服务注册与发现模块

为什么要服务注册&#xff0c;服务注册是做什么 服务注册主要是实现分布式的系统&#xff0c;让系统更加的健壮&#xff0c;一个节点主机将自己所能提供的服务&#xff0c;在注册中心进行登记 为什么要服务发现&#xff0c;服务发现是要做什么 rpc调用者需要知道哪个节点主机…

分布式缓存:应对突发流量的缓存体系构建

文章目录 缓存全景图Pre背景与目标说明缓存原则与设计思路缓存体系架构缓存预热与缓存预加载库存操作与缓存结合防刷、限流与缓存缓存一致性与失效异步落地与消息队列监控与指标容灾与扩展示例小结 缓存全景图 Pre 分布式缓存&#xff1a;缓存设计三大核心思想 分布式缓存&am…

华为云Flexus+DeepSeek征文|CCE容器高可用部署搭建Dify-LLM平台部署AI Agent

华为云FlexusDeepSeek征文&#xff5c;CCE容器高可用部署搭建Dify-LLM平台部署AI Agent 前言 Dify是一款开源的大语言模型应用开发平台&#xff0c;融合了后端即服务和LLMOps的理念&#xff0c;使开发者可以快速搭建生产级的生成式AI应用&#xff0c;本文将详细介绍如何使用华…

Postman 的 Jenkins 管理 - 手动构建

目录 一、准备工作 二、postman 项目脚本准备并导出 1. 打开已完成并测试无误的 postman 项目脚本。 再次执行测试。 ​编辑2. 导出&#xff08; 测试用例集、环境变量 两个文件&#xff09;**“不 支 持 中 文”** —— 全部改成英文&#xff01; ​编辑3. 文件所在目录…

音视频之H.264/AVC解码器的原理和实现

系列文章&#xff1a; 1、音视频之视频压缩技术及数字视频综述 2、音视频之视频压缩编码的基本原理 3、音视频之H.264/AVC编码器原理 4、音视频之H.264的句法和语义 5、音视频之H.264/AVC解码器的原理和实现 6、音视频之H.264视频编码传输及其在移动通信中的应用 7、音视…

【智能安全帽新升级】搭载VTX316TTS语音合成芯片,让安全“听得见”!

在工地轰鸣的机械声中&#xff0c;一句清晰的指令可能比任何文字都更有力量。 当智能安全帽遇上VTX316语音合成芯片&#xff0c;安全防护从“被动响应”进化为“主动交互”&#xff0c;为高危行业戴上了一顶“会说话的智慧大脑”&#xff01; 传统安全帽的“沉默”危机 在建筑…

【目标检测】非极大值抑制(NMS)的原理与实现

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

DB-GPT启动提示please install by running `pip install cryptography`

DB-GPT项目需要 cryptography 库来处理加密功能&#xff0c;但环境中没有安装它。cryptography 是一个用于安全和加密操作的Python库&#xff0c;许多项目&#xff08;包括DB-GPT&#xff09;依赖它来处理敏感数据的加密存储。 解决方案 1. 安装 cryptography 库 在激活的环…

局域网文件共享及检索系统

标题:局域网文件共享及检索系统 内容:1.摘要 随着信息技术的飞速发展&#xff0c;局域网在企业、学校等场景中得到广泛应用&#xff0c;大量文件在局域网内存储和流转。然而&#xff0c;目前局域网内文件共享与检索存在效率低、管理困难等问题。本文旨在设计并实现一个高效的局…

Spring Boot医疗系统高并发难题:达梦数据库死锁排查与优化实战

Spring Boot医疗系统高并发难题:达梦数据库死锁排查与优化实战 引言:医疗系统中的并发挑战 在现代医疗系统中,检查申请处理是关键业务场景之一,每天需要处理数以万计的检查记录。当多个操作同时更新同一患者的申请状态时,数据库层面的死锁问题成为高并发环境下的典型痛点…

Go语言中的文件与IO:bufio 和 scanner

Go 标准库中的 bufio 包提供了带缓冲的读写功能&#xff0c;可以显著提高文件和数据处理效率。而 bufio.Scanner 则是读取文本文件中每一行的利器&#xff0c;常用于日志、配置等文本处理场景。 一、为什么使用 bufio&#xff1f; 直接对文件进行 os.File.Read() 或 os.File.W…

ABP微服务架构中网关层NullReferenceException问题解析与HTTP配置优化

ABP微服务架构中网关层NullReferenceException问题解析与HTTP配置优化 一、网关层System.NullReferenceException问题解析 1.1 问题现象与原因分析 在ABP微服务架构开发过程中&#xff0c;网关层启动后调用微服务接口时出现以下异常&#xff1a; System.NullReferenceExcep…

啊啊啊啊啊啊啊啊code

前序遍历和中序遍历构建二叉树 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNod…

【算法 day06】LeetCode 454.四数相加II | 15. 三数之和 | 18. 四数之和

454.四数相加II 题目链接 | 文档讲解 |视频讲解 : 链接 1.思路&#xff1a; 0.定义一个count&#xff0c;计算最终出现的次数 1.先遍历nums1和nums2,求出两者的和&#xff0c;map的key是和&#xff0c;value是出现的次数 2.再遍历nums3和nums4&#xff0c;求出0-两者的和 3…

【项目实训】【项目博客#09】HarmonySmartCodingSystem系统后端智能API检索与代码助手实现(6.2-6.15)

【项目实训】【项目博客#09】HarmonySmartCodingSystem系统后端智能API检索与代码助手实现&#xff08;6.2-6.15&#xff09; 文章目录 【项目实训】【项目博客#09】HarmonySmartCodingSystem系统后端智能API检索与代码助手实现&#xff08;6.2-6.15&#xff09;项目博客概述一…

【JVM】- 类加载与字节码结构3

类加载阶段 1. 加载 加载&#xff1a;将类的字节码载入方法区中&#xff0c;内部采用C的instanceKlass描述java类。如果这个类的父类还没加载&#xff0c;则先加载父类加载和链接可能是交替运行的 通过全限定名获取字节码 从文件系统&#xff08;.class 文件&#xff09;、JA…

Qt蓝图式技能编辑器状态机模块设计与实现

设计概述 这个模块是一个基于Qt的蓝图式技能编辑器状态机&#xff0c;主要用于游戏开发中的技能状态管理。核心功能包括&#xff1a; 状态节点&#xff08;开始、结束、普通状态&#xff09;的可视化 状态间连线的绘制与管理 状态转换逻辑的可视化编辑 动作选择与配置 核…

Unity AR识别物体的内容语音读取+使用说明功能

因之前一直在开发项目&#xff0c;断断续续写了一点博客&#xff0c;最后统一写了一下博客记录学习内容。 可以看到我的工作一直在进行。 目录 一、识别内容语音读取 二、点击齿轮按钮弹出使用说明界面 开发步骤 1. 创建齿轮按钮 UI 2. 创建使用说明面板 UI 3. 编写控制…

Unable to start embedded Tomcat

通常是由于xml文件配置错误导致 1. mapper 指向错误 <resultMap id"Waybill" type"c.Waybill"> 2. 字段类型错误 <result column"wstatus" property"stus" javaType"TINYINT"/>TINYINT 是数据库类型<resu…