ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL 8.0 JDBC驱动Jar包:获取、配置与高频坑位排查

MySQL 8.0 JDBC驱动Jar包:获取、配置与高频坑位排查 MySQL 8.0版本的JDBC驱动Jar包几乎每个Java后端开发者都绕不开这个东西。我印象最深的一次是帮朋友排查一个老项目升级数据库从5.7换成8.0之后应用启动直接报ClassNotFoundException: com.mysql.jdbc.Driver排查了一圈才发现不是缺jar而是驱动类名变了。类似的问题在社区里层出不穷拿到新库、配好连接串、Maven一刷新启动时各种花式报错。这篇就围绕“MySQL 8.0版本JDBC驱动Jar包”这个主题把驱动的获取方式、项目导入、连接配置、框架集成和常见坑位全部过一遍。适合正在升级MySQL 8.0的Java开发者、IDEA新手以及被各种驱动异常折磨到怀疑人生的运维和数据分析同学。1. 核心梳理Java、JDBC、驱动Jar包三者到底是怎么协作的1.1 JDBC是一套规范MySQL驱动是这规范的实现刚接触Java连接数据库时很容易把JDBC和驱动混为一谈。JDBCJava Database Connectivity是Sun公司定义的一套Java访问数据库的标准接口它只规定了你应该怎么调用Connection、Statement、ResultSet这些接口长什么样、怎么用但JDBC自己不会连数据库。真正干活的是驱动MySQL的官方驱动叫Connector/J发布物就是一个Jar包。用生活里的例子来理解JDBC是电源插座的标准规格MySQL驱动是符合这个规格的插头MySQL服务器就是那台电器。你要给电器通电必须有正确的插头插进插座里。换个电器比如从MySQL换成PostgreSQL插座规格没变但插头要换成另一个牌子这就是为什么会有不同的JDBC驱动Jar包存在。具体到MySQL 8.0驱动Jar包的正式名称就是mysql-connector-j一个Jar包既包含了驱动类也包含了JDBC规范的实现代码。你的Java项目里只要有这个Jar包并且代码里正确加载驱动类就能通过JDBC接口操作MySQL 8.0数据库。注意JDK本身不包含任何数据库驱动只提供接口。这也是为什么任何数据库项目都要单独引入驱动依赖。1.2 MySQL 8.0的驱动相比5.x有一处必须重新认知的变动MySQL 8.0版本的驱动和5.x的驱动有一个非常显眼的区别驱动类名从com.mysql.jdbc.Driver变成了com.mysql.cj.jdbc.Driver。虽然旧类名在8.0驱动里仍然保留着但日志里会打出一段警告Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver。如果有人照搬网上的老教程用Class.forName(com.mysql.jdbc.Driver)加载8.0驱动代码不会报错但你会看到一段刺眼的警告日志而且新驱动里的很多行为默认值都和5.x不一样后续排查问题时容易被误导。所以升级到MySQL 8.0之后第一件事就是把代码里的驱动类名统一改成com.mysql.cj.jdbc.Driver。另外MySQL 8.0默认的认证插件从mysql_native_password换成了caching_sha2_password这也对驱动版本提出了硬性要求。如果你用很老的5.1.x驱动去连8.0库即使类名改对了也会在认证阶段报Public Key Retrieval is not allowed或者Unable to load authentication plugin caching_sha2_password。这些都是升级场景里最典型的组合坑。2. 获取Jar包的正确姿势Maven坐标比手动下载靠谱十倍2.1 首选Maven坐标引入别再手动去官网扒Jar了我见过太多新手在搜索引擎里找“MySQL驱动Jar包下载”下载到一个来历不明的Jar之后拖进项目里结果运行时期各种NoClassDefFoundError。这里强烈建议只要是Maven或Gradle项目一定用依赖坐标来管理驱动不要手动下载。Connector/J 8.0从8.0.31版本开始调整了Maven坐标新坐标是dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version8.0.33/version /dependencyGradle项目对应写法implementation com.mysql:mysql-connector-j:8.0.33如果项目里用的是8.0.31之前的坐标mysql:mysql-connector-java在8.0.31之后官方也已经做了迁移动向建议逐步换到新坐标。这里有个很容易忽略的细节旧坐标和新坐标的groupId、artifactId都不同如果项目里同时出现两个坐标会拉下来两个不同名字的Jar包类路径里出现重复的驱动类轻则警告重则版本冲突。用mvn dependency:tree检查一下依赖树只保留一个坐标。为什么强调用Maven而不是手动下载因为Maven会自动拉取传递依赖也能通过依赖冲突管理保证唯一版本。手动下载的Jar通常不知道编译版本、不知道配套依赖出了问题也很难追溯。而且Central仓库里的mysql-connector-j下载地址是公开固定的没必要走第三方下载站。2.2 不依赖Maven的场景IDEA导入Jar包的完整路径有些场景确实没法用Maven比如纯手工维护的Web项目或者公司内部老旧的构建体系。这时候你需要手动下载Jar并导入IDEA。下载地址建议直接用Maven Central仓库不要在搜索引擎里点来路不明的下载链接。以8.0.33为例Central上的路径是https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar下载完之后的导入步骤我按IDEA的操作路径拆开说打开IDEA菜单栏选中File-Project Structure或者直接按快捷键CtrlAltShiftS。在弹出的窗口左侧选择Modules选中你的模块右侧打开Dependencies标签页。点击底部或右侧的号选择JARs or directories。在文件选择框里定位到下载好的mysql-connector-j-8.0.33.jar确认选择。在依赖列表里确认这个Jar的Scope作用域类型普通项目选Compile即可这样它会被打包进编译和运行过程。点击OKIDEA会自动重新构建索引。如果你做的是Web应用部署到Tomcat这类外部容器时还需要特别注意一个问题驱动Jar要么打进WEB-INF/lib跟随WAR包走要么放进容器的lib目录。放进容器的lib会影响所有部署在容器里的应用一旦某个应用自己有另一个版本就会产生类加载冲突。我处理过好几次“本地IDEA运行正常部署到服务器就报找不到驱动”的案例最后都是因为Jar没有正确进入WEB-INF/lib。实操心得手动导入Jar后写一个最简单的JDBC连接测试类先跑通一次再继续写业务代码。不要等到项目启动到一半才发现驱动没生效那时候排查的成本高得多。2.3 驱动版本怎么选参考这张对照表很多人在版本选择上纠结其实只要记住三条经验MySQL 8.0的服务端推荐用Connector/J 8.0.x版本这是匹配度最高、踩坑最少的组合。如果还在用MySQL 5.6/5.7Connector/J 8.0.x也能向下兼容允许连5.x版本但不建议这么做老库老驱动更稳。版本号以8.0.x的小版本为主比如8.0.28、8.0.33、8.0.36这类稳定版本不要追最新的大版本例如随后可能会出现的9.x生产环境建议保持小版本稳定。服务端版本推荐驱动版本驱动类名备注MySQL 8.0Connector/J 8.0.28或更高com.mysql.cj.jdbc.Driver支持caching_sha2_password认证MySQL 5.7Connector/J 5.1.47com.mysql.jdbc.Driver老库老版本即可稳定优先MySQL 5.6Connector/J 5.1.xcom.mysql.jdbc.Driver同上MariaDB使用MariaDB官方驱动org.mariadb.jdbc.Driver不要用MySQL驱动连MariaDB协议有差异关于JDK版本Connector/J 8.0要求JDK 8或以上我在JDK 8、JDK 11和JDK 17上都实测过没有遇到兼容性问题。如果你还在用JDK 7或更早的版本老老实实用Connector/J 5.1系列吧。3. 连接配置实操一条JDBC URL里的参数都能要命3.1 连接URL逐段拆解useSSL、serverTimezone、allowPublicKeyRetrieval到底干嘛用的等到驱动Jar包就位下一步就是写出能跑通的连接URL。一个最典型的MySQL 8.0连接URL长这样jdbc:mysql://127.0.0.1:3306/test_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltruecharacterEncodingutf8我逐个参数讲讲它背后的意义因为这里踩坑的人实在太多了。首先是useSSLfalse。MySQL 8.0驱动的SSL默认行为是“如果服务端支持就用”但很多本地开发环境并没有配置SSL证书于是连接时会尝试SSL握手可能耗时更久甚至失败。开发环境直接关闭SSLuseSSLfalse就能解决这类问题。生产环境如果网络环境不需要加密或者你根本不知道证书怎么配也推荐直接关掉省去很多麻烦。如果是公网传输敏感数据建议开启并用证书。然后是serverTimezoneAsia/Shanghai。这个参数是为了告诉驱动数据库服务器所在时区。MySQL 8.0驱动对时区非常敏感如果不指定驱动会去读服务器的系统时区读出来如果是CST这种模糊缩写它可能是美国中部时间也可能是中国标准时间就会导致驱动在转换java.util.Date时出现偏差甚至直接报错。提示信息是The server time zone value CST is unrecognized or represents more than one time zone。国内服务器统一写Asia/Shanghai就行不要写GMT8这种偏移量用时区标准名更规范也避免夏令时差异。接着是allowPublicKeyRetrievaltrue。这个参数和MySQL 8.0的认证方式有关。当用户使用的认证插件是caching_sha2_password时如果连接是明文传输非SSL连接驱动必须从服务端获取RSA公钥来加密密码。默认情况下这个获取动作是被禁止的所以你会碰到Public Key Retrieval is not allowed。显式加上allowPublicKeyRetrievaltrue就允许驱动自动获取公钥。注意这个参数只在非SSL连接下是必须的如果你开了SSL证书密码传输走证书加密就不需要这个参数。最后是characterEncodingutf8。这个参数指定客户端与服务端通信时使用的字符集。MySQL 8.0的字符集默认是utf8mb4如果你在应用里存储了emoji表情必须确保连接参数和数据库表都是utf8mb4级别否则会出现“明明数据库没问题应用写入却报错或变成问号”的怪毛病。连接串里写characterEncodingutf8驱动会自动处理为可支持utf8mb4。参数作用强烈建议值useSSL是否启用SSL连接开发环境falseserverTimezone指定服务器时区Asia/ShanghaiallowPublicKeyRetrieval是否允许获取RSA公钥true非SSL时characterEncoding字符集utf8connectTimeout建立连接超时时间毫秒5000socketTimeout读写超时时间毫秒600003.2 跑通第一个最小JDBC连接Demo有了URL我们再写一个最基础的Java类来验证驱动是否正常工作。新建一个Mysql8JdbcDemo.java代码如下import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class Mysql8JdbcDemo { public static void main(String[] args) throws Exception { // 1. 加载驱动类MySQL 8.0的驱动类路径 Class.forName(com.mysql.cj.jdbc.Driver); // 2. 设置连接URL替换成你自己的库名、用户名、密码 String url jdbc:mysql://127.0.0.1:3306/test_db ?useSSLfalse serverTimezoneAsia/Shanghai allowPublicKeyRetrievaltrue characterEncodingutf8; String user root; String password your_password; // 3. 获取连接执行查询关闭资源 try (Connection conn DriverManager.getConnection(url, user, password); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(SELECT VERSION())) { if (rs.next()) { System.out.println(连接成功MySQL版本: rs.getString(1)); } } } }这段代码里的try-with-resources可以保证连接、Statement、ResultSet在结束后自动关闭如果你还在用老式的finally里手动close()也没有问题但要小心关闭顺序先关闭ResultSet再关Statement最后关Connection否则某些驱动在特殊情况下会抛连接关闭的异常。第一次跑通之后建议顺手在这个类里多试两条语句一条是不是SELECT的写操作一条带中文参数的SQL用来看字符集是否正常。很多坑其实是在“读英文一切正常读中文变成问号”时才暴露的早测早安心。3.3 框架集成Spring Boot和MyBatis的配置范例实际项目里大多数人不会手写JDBC而是通过Spring Boot、MyBatis这类框架来使用。这里以Spring Boot 2.7.x为例给出一个能直接落地的配置。在application.yml里这样写spring: datasource: url: jdbc:mysql://127.0.0.1:3306/test_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltruecharacterEncodingutf8 username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 2 connection-timeout: 30000Spring Boot的spring-boot-starter-jdbc或mybatis-spring-boot-starter会自动识别类路径里的mysql-connector-j所以很多时候driver-class-name实际上可以省略但写上更明确尤其排查驱动冲突时一眼就能看到配置对不对。关于连接池Spring Boot 2.x默认的HikariCP对MySQL 8.0支持得很好没有特殊情况不需要换连接池。有个小细节HikariCP强烈建议在URL里加上connectTimeout和socketTimeout否则当数据库服务短暂不可用时应用会一直卡在建立连接阶段看起来就像“假死”。我一般都会加上这两个参数配合connection-timeout一起设置。MyBatis的集成其实不需要额外改动配置上DataSource之后Mapper的正常CRUD就能跑起来。但要注意如果项目里同时引入了MyBatis Plus和原生MyBatis还要关注驱动依赖是否被覆盖。用mvn dependency:tree查看依赖树确保mysql-connector-j只有一个版本。4. 高频报错与排查实录这些问题我基本都亲眼见过4.1 ClassNotFoundException和deprecated警告背后常常是同一个原因先看最经典的一段报错java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver驱动类找不到的原因不外乎三个第一个是Jar包没有进入编译/运行类路径第二个是项目里虽然有驱动但是版本太老里面根本没有com.mysql.cj.jdbc.Driver这个类5.x驱动只有com.mysql.jdbc.Driver第三个是多个模块之间类加载冲突比如在Tomcat里同时存在不同版本的驱动Jar。排查顺序建议从简单到复杂先确认pom.xml里有没有依赖坐标再mvn dependency:tree确认有没有被打进最终产物再用jar tf mysql-connector-j-8.0.33.jar | grep cj/jdbc/Driver.class检查Jar包里到底有没有这个类。还有一个容易被忽略的情况如果你用的是旧驱动类名com.mysql.jdbc.Driver在新版驱动下运行不报错但会打印deprecated警告。这个警告虽然不影响功能但它提醒你代码该更新了。趁早把代码里所有Class.forName(com.mysql.jdbc.Driver)改成Class.forName(com.mysql.cj.jdbc.Driver)尤其是老项目迁移时别留这种隐患。注意在Spring Boot里你通常不需要调用Class.forName框架会通过SPI机制自动加载驱动。但如果你在普通Java程序或某些自行封装的结构里调用还是要显式加载。4.2 caching_sha2_password是MySQL 8.0的头号兼容挑战MySQL 8.0默认把所有新用户的认证插件设置成caching_sha2_password。这个插件安全性更高但也直接导致老驱动、旧工具连不上。最常见的报错有两种第一种是Public Key Retrieval is not allowed原因见前面URL参数的解释。解决办法很简单连接URL加allowPublicKeyRetrievaltrue。加密方式二选一要么加useSSLtrue用SSL传输密码要么加allowPublicKeyRetrievaltrue允许RSA公钥交换。开发环境我习惯两个一起加省得来回折腾。第二种是Unable to load authentication plugin caching_sha2_password。这个报错基本都是驱动版本太老导致的5.1.x老驱动内部根本没有这个插件的实现类。解决办法是换Connector/J 8.x驱动。如果你因为某些历史原因必须用老驱动那只能去服务端把这个用户的认证插件改回mysql_native_passwordALTER USER root% IDENTIFIED WITH mysql_native_password BY 你的密码;不过我不推荐把整库都改成老插件毕竟新插件安全性更好而且Connector/J 8.x完全支持。业务代码里只需要改一个依赖版本副作用最小。4.3 时区和SSL的翻车现场看起来是网络问题其实是配置缺失很多人第一次用MySQL 8.0驱动时会碰到下面这个让人摸不着头脑的报错java.sql.SQLException: The server time zone value Öйú±ê׼ʱ¼ä is unrecognized or represents more than one time zone.注意报错里那串乱码其实就是“中国标准时间”被以错误的字符集读取了。驱动默认去读服务端时区设置读回来的字符串它不认识。这种问题别去调MySQL全局time_zone除非你确定要改直接在连接URL里写死serverTimezoneAsia/Shanghai就可以了。时区还有一种隐蔽影响如果你服务端时区是UTC客户端是中国时区那么java.util.Date写入数据库后再读出来可能差8个小时这正是很多人吐槽“时间对不上”的原因。配置上serverTimezoneAsia/Shanghai后驱动就会明确按中国时区做日期转换问题当场消失。SSL相关的报错通常是Communications link failure或者SSL connection error。如果是本地开发数据库没有SSL证书直接加useSSLfalse。如果你用的连接池比如HikariCP还会额外打印“Establishing SSL connection without servers identity verification is not recommended”这种警告不用慌这只是一个提示不影响功能但强迫症也可以关掉SSL让它闭嘴。4.4 Flink、Hadoop这类大数据组件里的驱动冲突是个易踩的深坑在大数据组件里MySQL 8.0驱动问题也很常见。我自己遇到过Flink SQL作业连接MySQL 8.0时一直报Public Key Retrieval is not allowed最后发现Flink安装目录的lib下自带的驱动是mysql-connector-java-5.1.38.jar非常老。Flink SQL客户端和作业提交时会优先加载lib目录下的类而你作业里即使引入了新驱动也不一定生效因为类加载顺序的原因老驱动被优先加载了。解决办法是把新版本的mysql-connector-j-8.0.33.jar拷贝到$FLINK_HOME/lib目录删掉或替换掉自带的旧驱动然后重启Flink相关进程。注意只是把Jar丢进去还不够旧的还在的话会类冲突日志里出现各种诡异的NoSuchMethodError这种错误最坑因为它不会明确告诉你是哪个类冲突你需要用-verbose:class启动参数或者对比依赖树来找。Hadoop生态里类似的问题也普遍。比如导数据工具Sqoop连接MySQL 8.0时也会遇到认证方式和驱动版本不匹配解决思路完全一样找到工具实际使用的类路径把新驱动放到前端位置移除或忽略旧驱动。其实这类问题的根源就一句话MySQL 8.0服务端换认证插件后任何旧版本驱动都无法稳定连接而很多大数据组件默认携带的是老驱动。排查时不要光盯业务代码先检查组件自带的依赖。5. 我长期用下来的几个实操习惯文章到这里核心内容基本讲完了最后分享几个这些年我沉淀下来的操作习惯也算给看到这里的读者一点参考。第一任何项目都不手动管理驱动Jar包。能上Maven就一定上Maven依赖冲突至少可以靠工具排查。手动下载Jar包只用在离线环境、老式Web项目这种确实没有构建工具的场合。而且下载时只认官方Central仓库不从第三方下载站拿。第二每个项目提供一段“连通性自检代码”连接数据库的URL、账号、密码集中放到测试类或配置类里。有人问数据库连不上时直接让他跑这段测试代码几秒钟就能定位是网络问题、账号问题还是驱动问题省下大把沟通时间。第三升级MySQL 8.0时先改代码再改库变更顺序要规划好。驱动依赖、驱动类名、URL参数这三样东西必须同步升级缺一个都会踩坑。升级前把当前项目的依赖树、连接URL配置、代码里所有Class.forName位置都列出来逐项核对后再动手。第四别一次性升级跑全量回归。驱动升级看起来只是一个Jar包的替换但认证方式、时区处理、SSL行为、字符集行为全部会跟着变。我建议先把新驱动放到测试环境用连通性测试、基础CRUD、中文写入、时间读写、SSL检查几个维度过一遍确认全绿再上生产。MySQL 8.0的JDBC驱动不算难但它卡住的点非常集中几乎都是版本、认证、时区、SSL四类问题的排列组合。把这篇里的参数和排查思路记住以后再遇到连接报错先对照表格检查一遍比一个个查搜索引擎高效得多。
返回列表