MySQL Connector/J:mysql-connector-java与mysql-connector-j坐标迁移全指南
直接说结论mysql-connector-java和mysql-connector-j并不是两个不同的数据库驱动而是同一个 MySQL Connector/J JDBC 驱动的两种 Maven 坐标。前者是老名字后者是官方从 8.0.31 版本开始启用的新名字。旧坐标在 8.0.33 发布之后停止更新后续的功能迭代、安全修复、新版本号体系全部落到了新坐标上。但驱动类名、JDBC 连接串、API 用法完全一致绝大多数项目迁移时只需要改一下pom.xml或build.gradle里的依赖声明代码一行都不用动。这篇文章我会把这两个名字的来龙去脉、实际差异、迁移步骤和我踩过的坑一次讲清楚给正在做 Java MySQL 开发的人一个能直接照抄的结论。1. 先搞清楚这两个名字指的是同一个驱动1.1 Connector/J 在项目里到底扮演什么角色MySQL Connector/J 是 MySQL 官方推出的 Java 版数据库驱动实现的是 JDBC 规范。Java 程序要连 MySQL无论你是用DriverManager.getConnection()裸连还是走 Spring Boot JPA/Hibernate、MyBatis、MyBatis-Plus底层真正和 MySQL 实例建立 TCP 连接、发送协议包、解析返回结果的就是这个驱动。简单说它就是 Java 应用和 MySQL 之间的“翻译官”。它的工作流程其实很直白应用层通过连接池或DriverManager发起连接驱动把 JDBC 调用翻译成 MySQL 客户端/服务端协议消息通过网络发给 MySQL。连接起来之后驱动负责处理认证、字符集、事务状态、结果集元数据这些琐碎但对正确性至关重要的东西。所以驱动 jar 的版本对不对、依赖打包是否完整直接影响连接稳定性、传参正确性和安全性。很多人容易在这里被名字绕晕mysql-connector-java看起来像“专门的 Java 驱动”mysql-connector-j看起来像“某个新版本”。实际上它们背后是同一个项目、同一套源码、同一个版本号体系区别只是发布到 Maven 中央仓库时用的坐标写法发生了变化。1.2 命名演变的关键时间节点我梳理了几个关键节点理清楚之后就不会再混淆很长一段时间里官方发布 Connector/J 用的都是mysql:mysql-connector-java这个坐标版本从 3.x、5.1.x 一路走到 8.0.x。2022 年 10 月发布 8.0.31 时官方宣布启用新坐标com.mysql:mysql-connector-j并在新坐标下同步发布版本。旧坐标mysql:mysql-connector-java最后一次发布是 8.0.332023 年 1 月之后不再出新的版本。后续的 8.0.34、8.1、8.2、8.3、8.4 LTS、9.x 等版本都只以com.mysql:mysql-connector-j发布。换句话说如果某个项目里写的还是mysql:mysql-connector-java:8.0.33那已经是旧坐标的“绝版”版本如果看到com.mysql:mysql-connector-j:8.4.0这是新坐标下的长期支持版本。这两者本质是同一个驱动只是时代不同、名字不同。2. 表面与本质坐标不同功能几乎相同2.1 一张表看懂 Maven 坐标差异对比项旧坐标新坐标groupIdmysqlcom.mysqlartifactIdmysql-connector-javamysql-connector-j起始版本很早3.x 时代就有8.0.31旧坐标最终版本8.0.33仍在持续发布驱动类名com.mysql.cj.jdbc.Drivercom.mysql.cj.jdbc.DriverJDBC URL 前缀jdbc:mysql://jdbc:mysql://对应项目MySQL Connector/JMySQL Connector/J从表里能看到功能层面它们没有“型号”上的差异。8.0.x 的驱动类名都是com.mysql.cj.jdbc.Driver连接串格式也是jdbc:mysql://主机:端口/库名?参数。所以哪怕你直接把手头项目从旧坐标切到新坐标只要驱动版本号没有跨大版本比如从 5.1 直接跳到 8.xJava 代码基本不需要改。2.2 驱动类名和连接串为什么不用动这里专门说一下“代码不用改”的原因。JDBC 4.0 之后驱动 jar 通过META-INF/services/java.sql.Driver做服务发现Java 运行时会自动加载驱动。很多项目里已经不需要再写Class.forName(com.mysql.cj.jdbc.Driver)这种代码了。但如果你保留了这行注意 8.x 的类名是com.mysql.cj.jdbc.Driver别和 5.x 时代的com.mysql.jdbc.Driver搞混。这一点和坐标新旧没有关系8.0.30 用旧坐标类名是com.mysql.cj.jdbc.Driver8.0.31 用新坐标类名还是com.mysql.cj.jdbc.Driver。真正容易踩坑的是从 5.1.x 直接升到 8.x 的场景类名从com.mysql.jdbc.Driver变成了com.mysql.cj.jdbc.Driver配置里没改就会直接报ClassNotFoundException。JDBC URL 同样不变常见的写法是jdbc:mysql://localhost:3306/my_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiuseSSL/sslMode、serverTimezone、allowPublicKeyRetrieval、characterEncoding、rewriteBatchedStatements这些常用参数在新旧坐标下语义完全一致迁移时不需要调整。2.3 真正的功能差异依赖打包策略变了如果只看坐标和类名会觉得这纯粹是一次“改名运动”。实际上有一个值得关注的变化就是依赖打包策略。旧坐标下的mysql-connector-java并不是一个完全自洽的 jar。它的 POM 对外声明了第三方依赖最典型的是com.google.protobuf:protobuf-java这是 X DevAPI 也就是 MySQL X 协议能力需要用到的库。如果你的项目使用 X Protocol 连接mysqlx://这种协议用旧坐标时往往还要手动补 protobuf 依赖。更麻烦的是当项目里其他组件也用 protobuf且版本和驱动要求的版本冲突时会出现各种奇怪的NoClassDefFoundError或者“方法找不到”之类的问题。新坐标com.mysql:mysql-connector-j从 8.0.31 开始改成了“自包含”的打包方式把 X Protocol 需要的 protobuf 等第三方类重新定位relocate后打进驱动 jar 里。这样带来的直接好处是引入驱动时不再需要额外声明一堆间接依赖jar 扔到 classpath 就能用同一个应用里出现多个 protobuf 版本互相踩踏的概率也大幅降低。代价就是 jar 体积变大了一些因为内部多了被重新定位的类。用 Maven 查看依赖树能直观感受到这个差异。旧坐标的依赖树下会挂着com.google.protobuf:protobuf-java新坐标的依赖树基本是干净的几乎没有第三方 compile 依赖。这一点对于用mvn dependency:tree排查冲突的人来说区别非常明显。3. 为什么官方要改坐标三个必须知道的背景3.1 统一 Maven 命名空间MySQL 官方在 Maven 上发布的 Java 相关构件不少但历史上命名比较散。mysql-connector-java的 groupId 是mysql看起来像是一个非官方组织或个人维护的构件。改成com.mysql之后group 反域名命名规范和 Java 社区主流习惯一致也能让使用者一眼看出这是官方发布的东西。这个变化本质上是一次“身份标识”的规范化类似把一个项目从个人命名空间挪到官方命名空间。从使用者的角度讲groupId 变了对代码没有任何影响但会让依赖管理更清晰。尤其是在大型多模块项目里排查“这个 jar 到底是谁家的”会方便很多。3.2 让驱动变成一个自包含构件旧坐标时代的 Connector/J 虽然功能完整但依赖没有被“隔离”。最典型的就是 protobuf。如果你只是用传统 JDBC 方式连 MySQL可能根本感知不到 protobuf 的存在但只要用到 X DevAPI旧坐标就需要额外引入 protobuf-java版本还得小心对齐。新坐标从 8.0.31 开始把第三方类 relocate 进自身 jar相当于把一个需要“外部零件”的套装变成了“拆箱即用”的成品。这个设计对两类人特别友好一类是打 fat jar 或 shaded jar 的部署场景少一个间接依赖就少一个冲突源另一类是离线环境、内网私服环境构件越自包含拉依赖越省事。3.3 弃用规则与版本节奏MySQL 官方对 Connector/J 的版本节奏也有调整。以前 8.0.x 一路往下推很多用户分不清“驱动版本”和“MySQL 服务器版本”的对应关系。现在 Connector/J 跟随 MySQL 的版本策略分长期支持版LTS和创新版Innovation。LTS 版本如 8.4.x 适合生产环境创新版本如 9.x 适合尝鲜和验证新功能。旧坐标停止在 8.0.33意味着这个坐标下不会再有新的安全补丁和新特性。如果你的项目还在锁定mysql:mysql-connector-java,并且安全扫描工具开始对旧版本报高风险项通常的解决办法就是切换到新坐标、升级到最新 LTS 版本而不是继续在旧坐标里找更高版本号。4. 实操迁移从旧坐标切到新坐标4.1 Maven 项目替换步骤在pom.xml里找到旧的依赖声明把整段替换掉。旧写法dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.30/version /dependency新写法dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version8.4.0/version /dependency替换后建议执行一次完整构建确认没问题mvn clean verify如果项目里还有别的模块或父 POM 引用了mysql:mysql-connector-java可以用下面的命令查一下谁还在依赖它mvn dependency:tree -Dincludesmysql:mysql-connector-java查出来之后在对应间接依赖里加 exclusion避免新旧两个 jar 同时出现在 classpath。4.2 Gradle 项目替换步骤Gradle 项目的改法更简单。旧写法implementation mysql:mysql-connector-java:8.0.30新写法implementation com.mysql:mysql-connector-j:8.4.0改完可以用下面命令检查依赖情况./gradlew dependencies --configuration runtimeClasspath | grep mysql重点确认runtimeClasspath里只出现一个 MySQL 驱动坐标。如果新旧坐标同时出现说明有某个库通过传递依赖把旧坐标带进来了需要在该库的依赖声明里排除mysql:mysql-connector-java。4.3 Spring Boot 与 MyBatis 等框架中的迁移要点如果你用的是 Spring Boot连接配置里的driver-class-name不需要动仍然是spring.datasource.urljdbc:mysql://localhost:3306/my_db?useSSLfalseserverTimezoneAsia/Shanghai spring.datasource.usernameroot spring.datasource.passwordyour_password spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver需要注意的是Spring Boot 不同版本对 MySQL 驱动坐标的管理方式有差异。部分版本的依赖管理dependency management可能还在使用旧坐标mysql:mysql-connector-java并管理版本号。如果你在 Spring Boot 项目里手动覆盖驱动版本要连坐标带版本一起改只改 version 属性而坐标没换并不会真正切到新构件。用 MyBatis 或 MyBatis-Plus 的项目同理SqlSessionFactory配置、Mapper XML 里的内容完全不受影响改依赖坐标后重新启动应用验证连接即可。如果你用的是 JPA/Hibernate注意方言配置还是org.hibernate.dialect.MySQLDialect这类和驱动坐标无关。4.4 连接参数兼容性检查清单迁移后最容易出问题的其实不是坐标本身而是连接参数。我列一个常用参数检查清单照着核一遍基本不会翻车参数说明常见坑useSSL/sslMode是否启用 SSL旧项目可能设置useSSLfalse,新版本建议用sslModeDISABLED或PREFERREDserverTimezone服务器时区不设置可能报The server time zone value错误allowPublicKeyRetrieval是否允许获取公钥MySQL 8 默认认证插件为caching_sha2_password,连接工具客户端可能需要truecharacterEncoding字符集建议utf8或utf8mb4,避免中文乱码rewriteBatchedStatements是否重写批量语句批量插入性能优化常用开启需确认 SQL 语义兼容这些参数在新旧坐标下没有任何差异迁移时不需要改但如果你本来就是从一个很老的项目整体升级这些才是真正需要花时间核对的点。5. 踩坑实录与排查速查5.1 新旧两个 jar 同时出现在 classpath这是迁移过程中最常见的问题。某天项目里明明只声明了一个新坐标依赖但启动时出现类似“重复的类定义”或者驱动加载异常的报错十有八九是有个老库通过传递依赖把mysql:mysql-connector-java带进来了。排查思路分两步先用mvn dependency:tree -Dincludesmysql:mysql-connector-java或 Gradle 的dependencyInsight找到来源然后在对应的传递依赖上做排除dependency groupIdorg.example/groupId artifactIdsome-legacy-lib/artifactId exclusions exclusion groupIdmysql/groupId artifactIdmysql-connector-java/artifactId /exclusion /exclusions /dependency排除之后重新构建确认 classpath 里只剩com.mysql:mysql-connector-j。5.2 旧坐标 X DevAPI 时的 protobuf 报错如果项目使用 X Protocol 连接比如通过mysqlx://协议或者使用mysql-connector-j的部分高级模块并且还停留在旧坐标运行时会遇到类似NoClassDefFoundError: com/google/protobuf/...的报错。这是因为旧坐标下的 protobuf 依赖没有被内置而你的运行环境里恰好没有这个包。解决办法有两个要么切换新坐标让驱动自带的 relocate 版本生效要么临时补一个兼容版本的com.google.protobuf:protobuf-java依赖。前者是长期方案后者只是临时止血。我在实际项目里就遇到过 protobuf 版本和项目内其他组件冲突的情况最后是直接切到新坐标解决一劳永逸。5.3 从 5.1.x 升级到 8.x 时的类名陷阱这不是坐标新旧的问题但升级过程中特别容易踩。5.1.x 的驱动类名是com.mysql.jdbc.Driver8.x 是com.mysql.cj.jdbc.Driver。如果你把 8.x 的 jar 放进了 classpath但配置里还写着旧的类名启动时会直接报ClassNotFoundException: com.mysql.jdbc.Driver有些框架比如老版本 Spring Boot 的自动配置还会因为找不到驱动类而回退到猜测逻辑导致连接失败。排查时优先检查driver-class-name、hibernate.connection.driver_class这类配置项。5.4 迁移后连接报错的排查思路坐标改完、构建通过但应用启动时报连接异常这时候按顺序排查会比较快确认 classpath 里没有旧坐标残留用依赖树命令验证。确认 URL 参数没写错特别是serverTimezone和useSSL/sslMode。确认 MySQL 账号的认证插件。如果是caching_sha2_password且没有使用 SSL则通常需要allowPublicKeyRetrievaltrue。清掉本地 Maven 仓库里的旧缓存执行mvn -U clean verify重新拉取。如果应用服务器有多个模块检查公共 lib 目录里是否有旧版本的驱动 jar。5.5 常见问题速查表现象可能原因处理方式ClassNotFoundException: com.mysql.jdbc.Driver驱动类名用了 5.x 写法改为com.mysql.cj.jdbc.DriverThe server time zone value ...缺少时区参数URL 加serverTimezoneAsia/ShanghaiPublic Key Retrieval is not allowed认证插件为 caching_sha2_password 且未允许获取公钥URL 加allowPublicKeyRetrievaltrue启动时有类冲突告警新旧坐标同时存在排除旧坐标传递依赖X DevAPI 使用时报 protobuf 缺失旧坐标未内置 protobuf切换新坐标或手动补依赖依赖树出现两个 mysql 驱动传递依赖引入旧坐标在引入方排除旧坐标6. 新项目怎么选版本个人建议6.1 版本号规则简要解读MySQL Connector/J 现在的版本号规律可以简单理解成8.0.x 是成熟稳定的长线版本8.4.x 是官方标记的 LTS 长期支持版9.x 这类是创新版本、迭代更快但维护周期可能更短。如果你的项目是生产系统我建议优先考虑 LTS 系列如果只是个人学习或验证新功能用最新的创新版本也没问题。这和我们选 MySQL 服务器版本是一个思路生产环境求稳测试环境可以激进一点。连接参数、驱动类名在不同版本之间是稳定的所以即使后来想升级版本改动成本也很小。6.2 按场景选择依赖坐标项目状态推荐做法全新项目直接用com.mysql:mysql-connector-j选 LTS 版本老项目用旧坐标且没有异常尽快切到新坐标至少升级到 8.0.33 以上安全扫描拦截旧坐标升级到新坐标下受支持的最新 LTS 版本旧项目暂时不能动构建先记录技术债安排窗口升级不建议长期停留在旧坐标6.3 最后分享一点实际体会我在实际排查过的项目里见过最让人头疼的情况不是坐标差异本身而是项目里同时存在多个版本的 MySQL 驱动 jar导致排查一个简单的连接问题花掉半天时间。所以我的习惯是每接手一个 Java 项目第一件事就是跑一遍依赖树把所有数据库驱动的坐标、版本列出来确认一遍。这个习惯帮我在后续的升级和排障中省了很多事。如果你正在做的是新项目直接一步到位用新坐标如果是老项目把这次坐标切换当作一次顺手清理依赖的机会改完依赖后顺便把多余的传递依赖、过时参数一并清理掉。驱动这个环节稳定了后面查问题会轻松很多。