目录
- 核心概念与组件
- 准备工作
- 下载 JDBC 驱动
- 添加驱动到项目
- JDBC 连接数据库的七个标准步骤
- 完整代码示例 (MySQL)
- 处理不同类型的 SQL 语句
Statement(用于静态 SQL)PreparedStatement(推荐,用于动态 SQL,防止 SQL 注入)
- 最佳实践与资源管理
- 使用
try-with-resources(Java 7+) - 连接池 (如 HikariCP)
- 使用
核心概念与组件
在开始之前,需要了解几个核心接口和类:

Driver接口: 代表数据库驱动程序,每个数据库厂商(如 MySQL, Oracle)都会提供自己的Driver实现,JDBC 通过它来与特定的数据库进行通信。DriverManager类: 管理数据库驱动程序,它的主要作用是加载驱动程序,并建立与数据库的连接。Connection接口: 代表与数据库的连接,一个Connection对象会话,在这个会话中可以执行 SQL 语句和管理事务。Statement接口: 用于执行静态的 SQL 语句并返回它所生成结果。Statement有一个子接口PreparedStatement,功能更强大、更安全。ResultSet接口: 代表 SQL 查询语句返回的结果集,它是一个指向数据行的光标,可以通过next()方法向下移动。
准备工作
1 下载 JDBC 驱动
你需要为你所使用的数据库下载对应的 JDBC 驱动(通常是 JAR 文件)。
- MySQL: MySQL Connector/J
- PostgreSQL: PostgreSQL JDBC Driver
- Oracle: Oracle Database JDBC/ODBC Drivers
- SQL Server: Microsoft JDBC Driver for SQL Server
以 MySQL 为例,下载后你会得到一个类似 mysql-connector-j-8.0.xx.jar 的文件。
2 添加驱动到项目
你需要将下载的 JAR 文件添加到你的 Java 项目的类路径中。
-
使用 IDE (如 IntelliJ IDEA 或 Eclipse):
- 右键点击你的项目。
- 选择
Open Module Settings(IntelliJ) 或Build Path->Configure Build Path(Eclipse)。 - 在
Libraries或Modules->Dependencies选项卡中,点击Add External JARs...或Add JARs...。 - 选择你下载的 JDBC 驱动 JAR 文件。
-
使用 Maven: 在你的
pom.xml文件中添加依赖,Maven 会自动帮你下载和管理驱动。<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <!-- 使用你下载的版本号 --> </dependency>注意:新版本的 Maven 依赖 ID 已从
mysql-connector-java改为mysql-connector-j。 -
使用 Gradle: 在你的
build.gradle文件中添加依赖。implementation 'mysql:mysql-connector-java:8.0.33' // 使用你下载的版本号
JDBC 连接数据库的七个标准步骤
这是使用 JDBC 的经典流程:
- 加载驱动: 使用
Class.forName()方法加载数据库的驱动类,这会让 JVM 加载驱动类并注册到DriverManager中。 - 获取连接: 使用
DriverManager.getConnection()方法,提供数据库的 URL、用户名和密码,来创建一个Connection对象。 - 创建语句: 通过
Connection对象的createStatement()或prepareStatement()方法创建一个Statement或PreparedStatement对象。 - 执行语句: 使用
Statement或PreparedStatement对象的executeQuery()(用于查询) 或executeUpdate()(用于更新、插入、删除) 方法来执行 SQL。 - 处理结果: 如果执行的是查询,会返回一个
ResultSet对象,遍历ResultSet来获取数据。 - 关闭资源: 按照创建的相反顺序关闭
ResultSet、Statement和Connection。这一步至关重要,否则会导致数据库连接泄漏。 - 处理异常: 使用
try-catch-finally块来捕获和处理可能发生的SQLException。
完整代码示例 (MySQL)
假设我们有一个名为 testdb 的 MySQL 数据库,其中有一个 users 表:
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE
);
INSERT INTO users (name, email) VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com');
下面是一个完整的 Java 示例,连接这个数据库并查询所有用户。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcExample {
// 数据库连接信息
private static final String DB_URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASS = "your_password"; // 替换成你的数据库密码
public static void main(String[] args) {
// 1. 加载驱动 (现代JDBC驱动通常不需要显式调用 Class.forName)
// try {
// Class.forName("com.mysql.cj.jdbc.Driver");
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
// return;
// }
// 使用 try-with-resources 自动管理资源 (推荐)
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
// 2. 获取连接 (在 try-with-resources 的括号中完成)
// 3. 创建语句 (在 try-with-resources 的括号中完成)
// 4. 执行查询 (在 try-with-resources 的括号中完成)
System.out.println("ID\tName\tEmail");
System.out.println("--------------------");
// 5. 处理结果集
while (rs.next()) {
// 通过列名获取数据,更健壮
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
System.out.println(id + "\t" + name + "\t" + email);
}
} catch (SQLException e) {
// 6. 处理异常
System.err.println("数据库连接或查询出错!");
e.printStackTrace();
}
// 7. 关闭资源 (由 try-with-resources 自动完成)
}
}
代码说明:
DB_URL: 数据库的 URL。jdbc:mysql://: 协议和子协议。localhost:3306: 数据库服务器的地址和端口。/testdb: 要连接的数据库。?useSSL=false&serverTimezone=UTC: URL 参数,禁用 SSL (开发环境) 并设置时区。
try-with-resources: 这是 Java 7 引入的一个语法糖,任何实现了AutoCloseable接口的资源(如Connection,Statement,ResultSet)都可以放在try()语句中,无论try块是正常结束还是发生异常,这些资源都会被自动关闭,无需手动调用close(),从而避免了资源泄漏。
处理不同类型的 SQL 语句
1 Statement (用于静态 SQL)
上面的例子已经展示了 Statement 的用法,它适用于 SQL 语句内容固定不变的情况。注意:不要使用字符串拼接来构建 SQL,这极易引发 SQL 注入攻击。
// 错误示范 - SQL 注入风险! String username = "admin"; String sql = "SELECT * FROM users WHERE name = '" + username + "'"; // username 是 "admin' OR '1'='1",SQL 将变成 SELECT ... WHERE name = 'admin' OR '1'='1',会返回所有用户。
2 PreparedStatement (推荐,用于动态 SQL)
PreparedStatement 是 Statement 的子接口,用于执行预编译的 SQL 语句,它有两个主要优点:
- 防止 SQL 注入: 使用参数( 占位符)代替直接拼接字符串。
- 性能更高: 对于需要多次执行的 SQL(只是参数不同),数据库可以重用预编译的执行计划。
示例:使用 PreparedStatement 查询用户
// ... 同样的 DB_URL, USER, PASS ...
String sql = "SELECT id, name, email FROM users WHERE id = ?";
int userIdToFind = 1;
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
// 1. 创建 PreparedStatement 对象,并传入 SQL
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 2. 设置参数 (索引从 1 开始)
pstmt.setInt(1, userIdToFind);
// 3. 执行查询
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
System.out.println("找到用户: ID=" + rs.getInt("id")
+ ", Name=" + rs.getString("name"));
} else {
System.out.println("未找到 ID 为 " + userIdToFind + " 的用户。");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
最佳实践与资源管理
1 使用 try-with-resources (强制要求)
如前所述,这是现代 Java 开发中处理 JDBC 资源的标准做法,务必将所有 JDBC 对象都放在 try-with-resources 语句中。
2 连接池 (Connection Pool)
在真实的应用程序中,频繁地创建和销毁数据库连接是非常消耗性能的。连接池 应运而生。
连接池在应用启动时创建一组数据库连接,并保存在池中,当需要连接时,从池中获取一个用完后再放回池中,而不是关闭,这极大地提高了性能。
推荐使用 HikariCP,它目前是性能最好的 Java 连接池。
使用 HikariCP 的示例:
-
添加依赖 (Maven):
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> <!-- 使用最新版本 --> </dependency> -
代码示例:
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JdbcWithHikariCP { private static HikariDataSource dataSource; static { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC"); config.setUsername("root"); config.setPassword("your_password"); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); // 连接池配置 (可选) config.setMaximumPoolSize(10); // 最大连接数 config.setMinimumIdle(5); // 最小空闲连接数 config.setConnectionTimeout(30000); // 连接超时时间 (ms) dataSource = new HikariDataSource(config); } public static void main(String[] args) { String sql = "SELECT name FROM users WHERE id = ?"; try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, 1); try (ResultSet rs = pstmt.executeQuery()) { if (rs.next()) { System.out.println("用户名: " + rs.getString("name")); } } } catch (SQLException e) { e.printStackTrace(); } // 应用关闭时,关闭数据源 // dataSource.close(); } }
| 步骤 | 关键点 | 最佳实践 |
|---|---|---|
| 驱动 | Class.forName() 或自动加载 |
现代驱动通常无需显式加载,使用 Maven/Gradle 管理依赖。 |
| 连接 | DriverManager.getConnection() |
使用连接池 (如 HikariCP),避免频繁创建销毁连接。 |
| 语句 | createStatement() / prepareStatement() |
优先使用 PreparedStatement,防止 SQL 注入并提高性能。 |
| 执行 | executeQuery() / executeUpdate() |
根据操作类型选择正确的方法。 |
| 结果 | ResultSet.next() |
使用列名获取数据,比列索引更健壮。 |
| 关闭 | close() |
使用 try-with-resources,确保资源被自动、安全地关闭。 |
| 异常 | try-catch |
捕获 SQLException,并妥善处理,至少要打印堆栈信息。 |
遵循这些步骤和最佳实践,你就可以在 Java 应用中安全、高效地使用 JDBC 连接数据库了。
