mysql 8.0+ 必须用 mysql-connector-java 8.0.x(如8.0.33),驱动类名改为com.mysql.cj.jdbc.driver,jdbc url需显式指定characterencoding=utf-8和servertimezone=asia/shanghai,且class.forname()已冗余。

Java 连 MySQL 不是配个驱动就完事,mysql-connector-java 版本和 JDBC URL 写错,连 ClassNotFoundException 都不报,直接卡在 DriverManager.getConnection() 抛 SQLException。
怎么选对 mysql-connector-java 版本
MySQL 8.0+ 默认用 caching_sha2_password 插件鉴权,老驱动(比如 5.1.49)压根不认识——不是连不上,是认证阶段静默失败。
- MySQL 8.0+ → 必须用
mysql-connector-java8.0.x(如8.0.33),注意 groupId 已变:com.mysql(不是mysql) - MySQL 5.7 及更早 → 可用
5.1.49,但别用5.1.6这种十多年前的版本,SSL 和时区处理有坑 - Maven 里别写
runtimescope,test或默认compile才行,否则打包后找不到类
jdbc:mysql:// URL 里哪些参数不能省
URL 看似简单,少一个关键参数,连得上但查不出中文、时间错 8 小时、甚至被服务端主动断连。
- 必须显式加
?useUnicode=true&characterEncoding=UTF-8,否则String存中文变??? - MySQL 8.0+ 必须加
&serverTimezone=Asia/Shanghai,否则java.sql.Timestamp读出来慢 8 小时 - 开发环境建议加
&allowPublicKeyRetrieval=true&useSSL=false,否则可能卡在 RSA 密钥交换(尤其本地 Docker MySQL) - 别手抖写成
jdbc:mysql:/(少一个斜杠)或jdbc:mysql:://(多一个冒号),会报UnknownHostException
为什么 Class.forName("com.mysql.jdbc.Driver") 在新版本里没用了
JDBC 4.0+ 规范要求驱动自动注册,硬写这句不仅冗余,还可能触发 NoClassDefFoundError(因为新版驱动类名已改成 com.mysql.cj.jdbc.Driver)。
立即学习“Java免费学习笔记(深入)”;
- Java 8+ +
mysql-connector-java8.x → 完全删掉Class.forName(...),靠ServiceLoader自动加载 - 如果保留这行且类名写错(比如还写
com.mysql.jdbc.Driver),运行时报ClassNotFoundException,但错误栈藏在SQLException的 cause 里,容易漏看 - 真要手动加载,必须核对 JAR 包里的
META-INF/services/java.sql.Driver文件内容,以它为准
Connection 对象用完不关,到底会卡在哪
不是立刻报错,而是连接数慢慢涨满,后续 getConnection() 开始无限阻塞,日志里只看到线程卡在 awaitAvailable。
- 别信“JVM 退出时会自动关”,Web 应用跑着跑着就
Cannot create PoolableConnectionFactory - 用 try-with-resources 最稳:
try (Connection conn = DriverManager.getConnection(url, user, pwd); PreparedStatement ps = conn.prepareStatement("...")) { // ... } - 如果用 HikariCP 等连接池,
close()实际是归还连接,但漏写照样导致连接泄漏——池子满了就全队列挂起
最常被跳过的其实是时区和字符集参数,错一个,数据就悄悄变形;而驱动版本和 URL 的组合问题,往往要抓包或开 MySQL general_log 才能看出服务端到底收到了什么认证请求。











