⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 程序员江小北 「程序员江小北」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

摘要: 原创出处 https://www.iocoder.cn/Fight/no-title/ 「芋道源码」欢迎转载,保留摘要,谢谢!


背景简介

在一个老项目中,数据库采用的是 MySQL 5.7.36,ORM 框架使用的是 MyBatis 3.5.0,而 mysql-connector-java 的版本是 5.1.26。

有一天,一个精力充沛、充满折腾精神的年轻人加入了项目。

他觉得 MyBatis 的使用不够简单,需要写的代码比较多,因此认为有必要将其替换为 MyBatis-Plus。

MyBatis-Plus 替换 MyBatis

首先,我们准备了一张名为 tbl_order 的表,并初始化了其中的两条数据。

DROP TABLE IF EXISTS `tbl_order`;
CREATE TABLE `tbl_order` (
`id` bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`order_no` varchar(50) NOT NULL COMMENT '订单号',
`pay_time` datetime(3) DEFAULT NULL COMMENT '付款时间',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '最终修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '订单';

INSERT INTO `tbl_order` VALUES (1, '123456', '2024-02-21 18:38:32.000', '2024-02-21 18:37:34.000', '2024-02-21 18:40:01.720');
INSERT INTO `tbl_order` VALUES (2, '654321', '2024-02-21 19:33:32.000','2024-02-21 19:32:12.020', '2024-02-21 19:34:03.727');

为了简化演示,我们直接使用 MyBatis-Plus 构建了一个示例 demo,以此来模拟这位年轻人的替换过程。

我们只是简单地将 MyBatis-Plus 替换了 MyBatis,而其他组件的版本保持不变。

我们使用的 MyBatis-Plus 版本是这位年轻人引用的版本:3.1.1,

而 mysql-connector-java 的版本保持不变,仍然是 5.1.26。

示例代码:play_it_safe

然后,运行 com.qsl.OrderTest#orderListAllTest,却遇到了报错,异常信息如下所示:

请注意 Caused by 部分。

不支持的转换类型:java.time.LocalDateTime

是谁不支持呢?是 mysql-connector-java 不支持!

那么,哪个版本的 mysql-connector-java 支持呢?

❝

答案是:5.1.37

❞

升级 mysql-connector-java

我们将 mysql-connector-java 升级到 5.1.37,然后再次执行 com.qsl.OrderTest#orderListAllTest。

这次不再报异常,并且查询结果也是正确的。

看起来,MyBatis-Plus 替换 MyBatis 的任务完成了。

这一切都如此顺利,让人有些怀疑。

让我们再回头看看之前提到的异常:

Conversion not supported for type java.time.LocalDateTime

在替换 MyBatis 之前并没有这个异常,但在替换之后就出现了这个异常,这难道不是 MyBatis-Plus 的问题吗?

那么如何找到这个异常的根本原因呢?

其实很简单,直接从异常堆栈入手。

点击后,你会发现代码非常简单。

这么简单的代码怎么会有问题呢?

大家请注意图中左上角的 MyBatis 版本,是 3.5.1,而不是最初的 3.5.0。

可能有人会问:「既然替换成了 MyBatis-Plus,为什么还有 Mybatis 的存在?」

这个问题问得确实好,我只想给你个大嘴巴。

现在让我们看一下 MyBatis-Plus 的官方说明。

既然基于 Mybatis 3.5.0 没有抛出异常,而基于 3.5.1 却抛出了异常。

❝

“LocalDateTimeTypeHandler” 在 3.5.1 中肯定进行了调整

❞

那我们来看看调整了什么?

看出什么了吗?

MyBatis 3.5.0 会处理 LocalDateTime 类型的转换(将 java.sql.Timestamp 转换成 java.time.LocalDateTime)。

然而,注意了啊,最关键的地方来了!

从 MyBatis 3.5.1 开始,不再处理 LocalDateTime(还包括:LocalDate、LocalTime)类型的转换,而是交由 JDBC 组件,也就是 mysql-connector-java 来实现。

而巧的是:

❝

mysql-connector-java 5.1.26 不支持类型 LocalDateTime。

❞

那么它支持哪些类型呢?

我们同样从异常堆栈入手。

点击后,可以看到下图。

往上滑动鼠标,就可以看到支持的类型。

确实没有 LocalDateTime、LocalDate 和 LocalTime。

❝

mysql-connector-java 5.1.37 开始支持 LocalDateTime、LocalDate 和 LocalTime,前面已经介绍过了,不再赘述。

❞

总结异常根本原因:

❝

MyBatis 3.5.1 开始不再处理 LocalDateTime、LocalDate 和 LocalTime 的转换,而 mysql-connector-java 5.1.37 之前都不支持这些类型。

❞

搞清楚了这个异常的来龙去脉,顺理成章的感觉是不是又回来了?

暴风雨来临

版本上线不到两天,该来的终究还是来了。

我们往表 tbl_order 中插入了一条记录:

INSERT INTO tbl_order 
VALUES (3, 'asdfgh', NULL, '2024-02-21 20:01:31.111', '2024-02-21 20:02:56.764');

然后再次执行 com.qsl.OrderTest#orderListAllTest。

此时我就想问这位年轻人:爽不爽?

遇到了异常,那就找出原因。

同样从异常堆栈入手。

看出什么了吗?

如果 getTimestamp(columnIndex) 得到的是 NULL,那不就是 NullPointerException?这也太不严谨了吧?

修复问题是当务之急,先看哪个版本进行了修复?

将 mysql-connector-java 升级到 5.1.42。

问题得以修复。

❝

经过这一次事件,这位年轻人似乎成长了许多,但眼中的光却黯淡了不少。

❞

Mybatis-Plus 的问题

无意中我看到了这个 issue-1114,是不是和我们之前分析的 “Conversion not supported for type java.time.LocalDateTime” 是同一个问题?

只是我们使用的数据库连接池是默认的 HikariCP 而非 Druid。

结合 druid/issues/3302,如果使用 Druid 作为数据库连接池,出现的异常可能与我们之前分析的确实不同。

因此,大家需要根据自己的实际情况进行分析,但对异常的分析方法是通用的。

总结

关于组件的升级或旧代码的调整,都可能引发连锁反应,影响重大。

我的观点是:

❝

能不动就不要动,改好没功劳,改坏要背锅,吃力不讨好,又不是必须要改。

❞

如果不得不改,那就需要全面的测试。

文章目录
  1. 1. 背景简介
  2. 2. MyBatis-Plus 替换 MyBatis
  3. 3. 升级 mysql-connector-java
  4. 4. 暴风雨来临
  5. 5. Mybatis-Plus 的问题
  6. 6. 总结