- 核心概念:什么是 JDBC 和驱动?
- MySQL 驱动的演变:从
com.mysql.jdbc到com.mysql.cj - 如何获取 MySQL 驱动(JAR 包)
- 如何在项目中配置驱动(Maven/Gradle)
- 编写一个完整的连接示例
- 最佳实践:使用
try-with-resources - 常见问题与解决方案
核心概念:什么是 JDBC 和驱动?
- JDBC (Java Database Connectivity):这不是一个具体的库,而是一个Java API,一个规范,它定义了一套标准的方法和接口,允许 Java 程序与各种数据库进行交互,你可以把它想象成 Java 和数据库之间的“通用语言”或“桥梁”。
- 数据库驱动 (Driver):JDBC 本身只是个规范,它不能直接操作任何数据库。驱动是实现这个规范的具体代码,每个数据库厂商(如 Oracle, MySQL, PostgreSQL)都需要提供自己的驱动程序,这个驱动程序实现了 JDBC 接口,并知道如何与特定数据库的通信协议进行对话。
整个流程是:你的 Java 代码 -> JDBC API -> MySQL JDBC 驱动 -> MySQL 数据库。

MySQL 驱动的演变:com.mysql.jdbc vs com.mysql.cj
这是非常重要的一个知识点,因为很多老教程还在使用旧版驱动。
旧版驱动 (已过时)
- 包名:
com.mysql.jdbc - 驱动类名:
com.mysql.jdbc.Driver - 状态: 已弃用,从 MySQL Connector/J 5.1.6 版本开始,官方就标记为过时了。
- 问题: 它不支持一些新的标准,特别是 JDBC 4.1 规范,也无法正确处理时区等现代问题。
新版驱动 (当前标准)
- 包名:
com.mysql.cj(cj = Connector/J) - 驱动类名:
com.mysql.cj.jdbc.Driver - 状态: 当前推荐使用,从 Connector/J 6.0 版本开始成为默认驱动。
- 优点:
- 支持 JDBC 4.1/4.2 规范。
- 默认启用严格的模式,能更好地处理 SQL 语法错误和数据类型不匹配问题。
- 正确处理服务器时区和客户端时区,避免了
The server time zone value 'XXX' is unrecognized这个常见的错误。 - 性能更好,安全性更高。
请务必使用新版驱动 (com.mysql.cj.jdbc.Driver)。
如何获取 MySQL 驱动(JAR 包)
你可以从 MySQL 官网下载驱动 JAR 包。
- 访问 MySQL Connector/J 下载页面。
- 选择 "Platform Independent" (平台独立) 版本,下载 ZIP 压缩包。
- 解压后,你会找到一个名为
mysql-connector-j-8.0.xx.jar(版本号可能不同) 的文件,这就是你需要的驱动 JAR。
如何在项目中配置驱动(推荐方式)
手动下载 JAR 包并添加到项目库中很麻烦,现代项目构建工具可以自动处理依赖。

使用 Maven (最常用)
在你的 pom.xml 文件中添加以下依赖,Maven 会自动从中央仓库下载最新的驱动。
<dependencies>
<!-- MySQL Connector/J 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 建议使用最新稳定版 -->
<!--
scope: runtime 表示这个依赖只在运行时需要,编译和测试时不需要。
这可以减少传递性依赖,让项目更干净。
-->
<scope>runtime</scope>
</dependency>
</dependencies>
使用 Gradle
在你的 build.gradle 或 build.gradle.kts 文件中添加以下依赖。
// build.gradle (Groovy DSL)
dependencies {
// MySQL Connector/J 驱动
runtimeOnly 'com.mysql:mysql-connector-j:8.0.33' // 建议使用最新稳定版
}
// build.gradle.kts (Kotlin DSL)
dependencies {
// MySQL Connector/J 驱动
runtimeOnly("com.mysql:mysql-connector-j:8.0.33") // 建议使用最新稳定版
}
编写一个完整的连接示例
下面是一个完整的 Java 代码示例,展示了如何使用新版驱动连接到 MySQL 数据库。
准备工作:

- 确保你有一个正在运行的 MySQL 服务。
- 在 MySQL 中创建一个数据库和用户,并授予相应权限。
CREATE DATABASE mytestdb; CREATE USER 'javauser'@'localhost' IDENTIFIED BY 'password123'; GRANT ALL PRIVILEGES ON mytestdb.* TO 'javauser'@'localhost'; FLUSH PRIVILEGES;
Java 代码示例:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class MysqlJdbcExample {
// 数据库连接信息 - 建议从配置文件中读取,而不是硬编码
private static final String DB_URL = "jdbc:mysql://localhost:3306/mytestdb";
private static final String USER = "javauser";
private static final String PASS = "password123";
public static void main(String[] args) {
// JDBC 驱动类名 - 对于新版驱动
// 注意:从 JDBC 4.0 开始(Java 6+),通常不需要显式加载驱动类了
// Class.forName("com.mysql.cj.jdbc.Driver");
// try-with-resources 语句会自动关闭 Connection 和 Statement
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement()) {
if (conn != null) {
System.out.println("成功连接到 MySQL 数据库!");
}
// --- 执行一个简单的查询 ---
System.out.println("\n--- 执行查询 ---");
String sql = "SELECT 'Hello, MySQL!' AS message";
var rs = stmt.executeQuery(sql);
if (rs.next()) {
System.out.println("查询结果: " + rs.getString("message"));
}
// --- 执行一个插入操作 ---
System.out.println("\n--- 执行插入 ---");
String insertSql = "INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com')";
int affectedRows = stmt.executeUpdate(insertSql);
if (affectedRows > 0) {
System.out.println(affectedRows + " 行数据插入成功。");
}
} catch (SQLException e) {
// 捕获并处理 SQL 异常
System.err.println("数据库连接或操作失败!");
e.printStackTrace();
}
// conn 和 stmt 会在这里自动关闭
}
}
连接 URL (JDBC URL) 解析
jdbc:mysql://localhost:3306/mytestdb 这部分是关键:
jdbc:mysql://: 协议头,表示使用 MySQL 的 JDBC 连接。localhost: 数据库服务器的地址,如果是远程服务器,就换成 IP 或域名。3306: MySQL 的默认端口号,如果你的 MySQL 配置了不同端口,需要相应修改。/mytestdb: 要连接的具体数据库名。
对于新版驱动,强烈建议在 URL 后面加上时区参数,以防万一:
jdbc:mysql://localhost:3306/mytestdb?serverTimezone=UTC
或者使用你的服务器时区,Asia/Shanghai。
最佳实践:使用 try-with-resources
在上面的代码中,我们使用了 try-with-resources 语句,这是 Java 7 引入的一个非常重要的特性。
- 为什么需要它? 数据库连接(
Connection)、语句(Statement/PreparedStatement)和结果集(ResultSet)都是需要系统资源的有限资源,使用完毕后,必须显式地关闭它们,否则会导致资源泄漏,最终可能使应用程序崩溃。 - 传统方式:在
finally块中调用close()方法,但代码冗长且容易出错。 try-with-resources:任何实现了AutoCloseable接口的对象都可以在try语句中声明,当代码块执行完毕后(无论是正常结束还是发生异常),这些对象都会被自动调用close()方法。
优点:
- 代码简洁:无需编写冗长的
finally块。 - 安全可靠:能确保资源被正确关闭,即使在
try块中发生了异常。
常见问题与解决方案
Q1: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
原因: JVM 在运行时找不到 MySQL 驱动的类文件。 解决方案:
- 检查依赖:如果你使用 Maven/Gradle,确保
pom.xml或build.gradle中的依赖配置正确,并且已经执行了mvn install或gradle build。 - 检查 JAR 包:如果你是手动添加 JAR,确保它位于项目的类路径(Classpath)中,在 IDE(如 IntelliJ IDEA 或 Eclipse)中,检查库是否已正确添加到项目模块中。
Q2: The server time zone value 'XXX' is unrecognized or represents more than one time zone.
原因: 这是最常见的错误之一,新版驱动默认会检查服务器时区,但服务器返回的时区信息可能不被 JVM 识别。 解决方案: 在 JDBC URL 中明确指定服务器时区。
String DB_URL = "jdbc:mysql://localhost:3306/mytestdb?serverTimezone=UTC"; // 或者 String DB_URL = "jdbc:mysql://localhost:3306/mytestdb?serverTimezone=Asia/Shanghai";
Q3: Access denied for user 'user'@'host'
原因: 数据库用户名或密码错误,或者该用户没有从你的客户端机器连接到数据库的权限。 解决方案:
- 检查
USER和PASS变量是否正确。 - 登录 MySQL,检查用户权限:
SHOW GRANTS FOR 'javauser'@'localhost';,确保有GRANT ALL PRIVILEGES ON mytestdb.* TO ...这样的权限。
Q4: Communications link failure
原因: Java 应用程序无法与 MySQL 服务器建立网络连接。 解决方案:
- 检查 MySQL 服务是否正在运行,可以使用
mysql -u root -p命令尝试登录。 - 检查地址和端口:确认
localhost和3306是正确的,MySQL 服务器在其他机器上,请使用正确的 IP 地址。 - 检查防火墙:确保服务器的防火墙没有阻止 3306 端口的入站连接。
