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

给分库分表的 ShardingSphere 提了个PR,这Bug居然改了

说来惭愧,干了 10 来年程序员,还没有给开源做过任何贡献,以前只知道嘎嘎写,出了问题嘎嘎改,从来没想过提个 PR 去修复他,最近碰到个问题,发现挺简单的,就随手提了个 PR 过去。

问题

问题挺简单的,就是在使用 mybatis 和 ShardingSphere 的时候,有人在 model 类使用了OffsetDateTime这个时间类型,发现会报错。

Caused by: java.lang.ClassCastException: class java.sql.Timestamp cannot be cast to class java.time.OffsetDateTime (java.sql.Timestamp is in module java.sql of loader 'platform'; java.time.OffsetDateTime is in module java.base of loader 'bootstrap') at org.apache.ibatis.type.OffsetDateTimeTypeHandler.getNullableResult(OffsetDateTimeTypeHandler.java:38) at org.apache.ibatis.type.OffsetDateTimeTypeHandler.getNullableResult(OffsetDateTimeTypeHandler.java:28) at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) ... 99 more

这就是一个简单的类型转换的异常,于是跟着源码看了下,先看到BaseTypeHandler#getResult这个方法,实际上就是根据列名返回查询结果。

根据调用关系,找到了OffsetDateTimeTypeHandler实现类。

发现最终会调用rs.getObject()这个方法,那么其实这个方法会最终走到由 ShardingSphere 实现的getObject方法中。

看到这里的时候其实已经明白了为啥会报错了,Shardingsphere 只判断了几个LocalDateTime等类型,对于这个比较特殊的时间类型没有处理,最终会转换成 Timestamp ,然后强转就报错了。

最后调用到ResultSetUtil#convertTimestampValue方法,可以看到确实是这样哈。

那如果修改源码的话其实很简单了,getObject判断多加一个,convertTimestampValue再加一个,就这样很简单啊。

@Override public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException { if (BigInteger.class.equals(type)) { return (T) BigInteger.valueOf(getLong(columnIndex)); } else if (Blob.class.equals(type)) { return (T) getBlob(columnIndex); } else if (Clob.class.equals(type)) { return (T) getClob(columnIndex); } else if (LocalDateTime.class.equals(type) || LocalDate.class.equals(type) || LocalTime.class.equals(type) || OffsetDateTime.class.equals(type)) { return (T) ResultSetUtil.convertValue(mergeResultSet.getValue(columnIndex, Timestamp.class), type); } else { return (T) ResultSetUtil.convertValue(mergeResultSet.getValue(columnIndex, type), type); } } private static Object convertTimestampValue(final Object value, final Class<?> convertType) { Timestamp timestamp = (Timestamp) value; if (LocalDateTime.class.equals(convertType)) { return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); } if (LocalDate.class.equals(convertType)) { return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); } if (LocalTime.class.equals(convertType)) { return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalTime(); } if (OffsetDateTime.class.equals(convertType)) { return timestamp.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime(); } return value; }

修复

最开始我其实并不想改源码,我在想其他的实现方案,搜索后发现引入一个包就可以解决,也就是 mybatis 的 JSR310 规范。

<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-typehandlers-jsr310</artifactId> <version>1.0.1</version> </dependency>

他为什么能解决这个问题?我看了下他的包里面的代码,这不就是加了个 TypeHandler 自己处理了嘛。

再去看了下OffsetDateTimeTypeHandler的实现,其实就是自己就解决了,直接给返回OffsetDateTime,根本不会走到 ShardingSphere 的逻辑里面去,这也就是他能解决这个问题的原因了。

当然,如果不想那么麻烦引入一个包,也可以单独把他拎出来自己去指定一下,这个很简单,就不多说了。

提PR

于是我想,这事情这么简单,我不如提个 PR 给官方吧,这里教下大家怎么提 PR 。

因为不是咱们的项目,是没法 push 代码的,所以进入到项目,然后fork,fork 好了以后,直接把项目 clone 下来,然后执行命令。

git remote add upstream https://github.com/apache/shardingsphere.git

通过命令我们可以看到成功了,这样就 OK了,然后正常拉分支写代码吧。

写完之后,正常去我们的项目界面提交 PR,然后就可以了。

麻烦

当然,过程并没有这么顺利,虽然说只是很简单的修改。

首先,这个校验就给我提示错误了,第一点叫我不要用*号去引用。

这个其实是IDEA的锅,如果引用同一个包下类过多的话,会自动帮我们转成星号,这个我们可以在Editor-Code Style-Java,然后找到 Imports 下的这两个选项,把他们都改成 99 就可以了,防止他自动给我们改成星号。

还有一些其他的比如 if 后面没跟空格之类的,这是我忘记格式化了!

然后大佬回复觉得看不下去,这代码太恶心了,说我们是不是可以用java.time.temporal.TemporalAccessor来判断,不然这么多时间类型,搞个毛线呢。

然后我就翻译了一段英文,我也不知道大佬看没看懂,我告诉他,这个不好整啊,你看这个接口啊,很多乱七八糟的类实现了他,实际上我觉得我们覆盖常用的一些就行了,其他的特殊时间类型让他们自己用 TypeHandler 处理吧。

大佬说,嗯当然,没办法判断这个接口那我们也没辙了,我说那不可就是嘛。

其实,还有很多时间类型他都会报错的,最好的办法这个都抽象出来和Mybatis单独用实现类,不过那样的话就得大工作了,我太懒了,就这样。

。。。

最后要看了一下,大佬们已经把这个bug Fixed了,我这也算是为开源做过贡献的人了,身上光环锃亮!!!

http://www.jsqmd.com/news/440436/

相关文章:

  • 计算机
  • 分库分表后如何设计索引?全局索引、二级索引
  • SpringCloud + RocketMQ 实现分布式事务,稳的一批
  • LoRA爆了?这篇论文硬核打脸!纯LoRA知识库路线要凉?真相竟是它…(附实验证明)
  • AI大模型卷向超长上下文:从参数规模到上下文长度,谁才是AI智能的关键?
  • OpenClaw火爆出圈!246K星!硬核拆解本地化AI助理架构,企业级Agent架构演进至17层!
  • 收藏!AI大模型时代,产品经理需要了解什么?
  • 2026年湖南浏阳展览模型行业标杆推荐:建筑沙盘模型、道路与桥梁模型、新能源发电模型、核能发电模型、地质地貌模型、浏阳湘东科技展览模型 - 海棠依旧大
  • 2026年 沙盘模型厂家推荐排行榜,房地产/地形地貌/城市区域规划/工业机械/军事/电子数字/农业文旅沙盘,专业定制与视觉创意深度解析 - 品牌企业推荐师(官方)
  • 一文搞懂 AQS (AbstractQueuedSynchronizer 抽象队列同步器 )的原理
  • 湘东科技厂家供应各类仿真展览模型:沙盘模型、锅炉模型、水轮机模型、汽轮机模型、水利水电模型、火力发电模型、发电厂电气模型 - 海棠依旧大
  • MyBatis-配置文件解读及MyBatis为何不用编写Mapper接口的实现类
  • 2026年全国磷虾油品牌优选指南 五大品质品牌参考 - 十大品牌榜
  • Flutter 三方库 jaspr_riverpod 的鸿蒙化适配指南 - 打造全栈响应式架构、Riverpod 状态管理实战、鸿蒙级 Web 开发重器
  • C#文件操作思维导图
  • 2026广东广州天然原矿绿松石五大厂家实力排行榜 - 十大品牌榜
  • 2026年全国高磷脂磷虾油品牌优选指南 五大品质公司参考 - 十大品牌榜
  • 2026年不锈钢管厂家推荐排行榜,304L/316L/2205不锈钢管、焊接/无缝不锈钢管,精选优质耐腐蚀工业管材品牌 - 品牌企业推荐师(官方)
  • 园区综合能源系统的能量管理:一个有趣的小探索
  • 2026年 隔音门厂家推荐排行榜:卧室/医院/实木/室内/极简/酒店/家用/客厅/防火/房间隔音门,专业定制与静音性能深度解析 - 品牌企业推荐师(官方)
  • 2026年广东广州绿松石厂家优选指南 四大品质企业参考 - 十大品牌榜
  • C++ 继承:面向对象的代码复用核心机制
  • 关系到系统上线后的可用性与稳定性。而性能测试报告,作为承载测试结论、问题分析与优化建议的核心输出,决定了性能评估的专业性与决策价值。 ...
  • JDK源码之Object
  • 2026年黑龙江管材推荐厂家:MPP电力保护管、通信管、电力管、给水管、排水管、排污管、塑料管、硅芯管等各类塑料管材 - 海棠依旧大
  • 2026年广东广州沉香手串厂家优选指南 十大品质品牌参考 - 十大品牌榜
  • 飞算科技,让代码飞:欢迎体验 JavaAI 开发助手,参加炫技赛
  • 2026年3月全国脑抗衰培训机构广东深圳实力排行榜:基于专业体系与市场口碑的五大权威推荐榜单 - 十大品牌榜
  • 2026 中专大数据技术专业考证书门槛低的有哪些
  • 2026年全国脑抗衰培训品牌广东深圳优选指南 五大品质品牌参考 - 十大品牌榜