目录
- 准备工作
- 核心概念:JDBC
- 使用 JDBC 驱动(传统方式)
- 步骤详解
- 完整代码示例
- 优缺点分析
- 使用连接池(推荐方式)
- 什么是连接池?
- 使用 HikariCP(目前性能最好的连接池)
- 完整代码示例
- 最佳实践与注意事项
- 务必使用
try-with-resources - 务必使用
PreparedStatement - 配置文件管理
- 异常处理
- 务必使用
- 如何选择?
准备工作
在开始写 Java 代码之前,请确保你已经准备好了以下环境:

- Java 开发环境 (JDK): 确保你的系统已经安装了 JDK 并且配置了
JAVA_HOME环境变量。 - MySQL 数据库: 安装并运行着 MySQL 服务器。
- MySQL 数据和用户:
- 创建一个用于测试的数据库,
test_db。 - 在该数据库中创建一张表,
users。 - 创建一个可以访问该数据库的用户,
java_user,并设置密码(password123)。 - 给该用户授予
test_db数据库的访问权限。
- 创建一个用于测试的数据库,
- MySQL JDBC 驱动: 这是 Java 连接 MySQL 的桥梁,你需要下载对应的驱动 Jar 包。
- 下载地址: MySQL Connector/J
- 选择平台无关的版本(Platform Independent),下载一个
.zip或.tar.gz文件。 - 解压后,你会找到一个名为
mysql-connector-j-版本号.jar的文件,这个就是我们需要的驱动。
核心概念:JDBC
JDBC (Java Database Connectivity) 是 Java API,它定义了客户端如何访问数据库,它本身并不实现数据库连接,而是提供了一套标准接口,数据库厂商(如 MySQL、Oracle)会提供这些接口的实现,也就是我们下载的 JDBC 驱动。
JDBC 是 Java 与数据库沟通的“通用语言”。
方法一:使用 JDBC 驱动(传统方式)
这是最基础的方式,理解它有助于你理解连接的本质。
步骤详解
- 加载 JDBC 驱动: 使用
Class.forName()将驱动类的实现加载到 JVM 中。 - 获取数据库连接: 使用
DriverManager.getConnection()方法,提供数据库的 URL、用户名和密码来建立连接。 - 创建 Statement 对象: 通过连接对象创建一个
Statement或PreparedStatement对象,用于执行 SQL 语句。 - 执行 SQL 查询: 调用
Statement对象的executeQuery()方法(用于查询)或executeUpdate()方法(用于增删改)。 - 处理结果集: 如果是查询操作,会返回一个
ResultSet对象,你需要遍历它来获取数据。 - 关闭资源: 非常重要! 按照创建的逆序关闭所有资源:
ResultSet->Statement->Connection,如果不关闭,会导致数据库连接泄漏,最终耗尽数据库资源。
完整代码示例
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/test_db?useSSL=false&serverTimezone=UTC";
private static final String USER = "java_user";
private static final String PASS = "password123";
public static void main(String[] args) {
// 1. 加载 JDBC 驱动 (MySQL 8+ 的驱动类名)
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.err.println("找不到 MySQL JDBC 驱动,请确保驱动在 classpath 中。");
e.printStackTrace();
return;
}
// try-with-resources 语句 (Java 7+),可以自动关闭资源
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
System.out.println("成功连接到数据库!");
System.out.println("ID\tName\tEmail");
// 3. 遍历结果集
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) {
System.err.println("数据库连接或查询出错!");
e.printStackTrace();
}
}
}
如何运行
- 将下载的
mysql-connector-j-版本号.jar文件复制到你的项目目录下。 - 如果你使用 IDE(如 IntelliJ IDEA 或 Eclipse),右键点击这个 Jar 文件,选择 "Add as Library" 或 "Add to Build Path"。
- 运行
JdbcExample.java。
优缺点分析
- 优点: 简单直接,易于理解。
- 缺点:
- 性能差: 每次请求都创建一个新的连接,销毁一个连接,开销巨大。
- 资源浪费: 高并发下会迅速耗尽数据库的连接资源。
- 代码冗余: 每次连接都需要重复加载驱动、建立连接的代码。
方法二:使用连接池(推荐方式)
为了解决传统方式的性能问题,我们引入 数据库连接池。

什么是连接池?
连接池是一个管理数据库连接的“池子”,应用程序启动时,它会预先创建一定数量的连接并放入池中,当需要连接时,从池中“借用”一个,用完后“归还”给池子,而不是销毁,这样就避免了频繁创建和销毁连接的开销,极大地提升了性能。
使用 HikariCP(目前性能最好的连接池)
HikariCP 是目前公认性能最高、稳定性最好的 JDBC 连接池。
添加依赖
如果你使用 Maven,在 pom.xml 中添加 HikariCP 和 MySQL 驱动的依赖:

<dependencies>
<!-- HikariCP 连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version> <!-- 使用最新版本 -->
</dependency>
<!-- MySQL JDBC 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 使用与数据库匹配的版本 -->
</dependency>
</dependencies>
如果你使用 Gradle,在 build.gradle 中添加:
dependencies {
// HikariCP 连接池
implementation 'com.zaxxer:HikariCP:5.0.1'
// MySQL JDBC 驱动
implementation 'com.mysql:mysql-connector-j:8.0.33'
}
完整代码示例
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class HikariCPExample {
// 使用 HikariDataSource 作为数据源
private static HikariDataSource dataSource;
// 静态代码块,在类加载时初始化连接池
static {
HikariConfig config = new HikariConfig();
// --- 配置信息 ---
config.setJdbcUrl("jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC");
config.setUsername("java_user");
config.setPassword("password123");
// 连接池配置
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMaximumPoolSize(10); // 最大连接数
config.setMinimumIdle(5); // 最小空闲连接数
config.setConnectionTimeout(30000); // 连接超时时间 (毫秒)
config.setIdleTimeout(600000); // 空闲连接超时时间 (毫秒)
config.setMaxLifetime(1800000); // 连接最大存活时间 (毫秒)
dataSource = new HikariDataSource(config);
}
public static void main(String[] args) {
// 从连接池获取一个连接
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
System.out.println("成功从连接池获取连接!");
System.out.println("ID\tName\tEmail");
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) {
System.err.println("从连接池获取连接或查询出错!");
e.printStackTrace();
}
// 在应用程序关闭时,关闭连接池
if (dataSource != null && !dataSource.isClosed()) {
dataSource.close();
}
}
}
最佳实践与注意事项
务必使用 try-with-resources
从 Java 7 开始,try-with-resources 语句可以自动实现 AutoCloseable 接口的资源关闭。强烈推荐使用它,它能确保 Connection, Statement, ResultSet 等资源在任何情况下都会被正确关闭,即使发生异常。
// 推荐
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
// ...
} catch (SQLException e) {
// ...
}
// 不推荐(容易忘记关闭)
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = dataSource.getConnection();
pstmt = conn.prepareStatement("...");
} catch (SQLException e) {
// ...
} finally {
// 必须手动关闭,且要处理嵌套的 try-catch
if (pstmt != null) try { pstmt.close(); } catch (SQLException e) { /* log */ }
if (conn != null) try { conn.close(); } catch (SQLException e) { /* log */ }
}
务必使用 PreparedStatement
PreparedStatement 是预编译的 SQL 语句,它有两大好处:
- 防止 SQL 注入: 它会将参数作为数据处理,而不是 SQL 代码的一部分,从而有效防止恶意 SQL 注入攻击。
- 性能更好: 对于需要多次执行的 SQL(只是参数不同),数据库可以重用预编译的执行计划,提高效率。
// 使用 Statement (不安全)
String sql = "SELECT * FROM users WHERE name = '" + userName + "'";
// userName 是 "admin' OR '1'='1",SQL 就会被篡改。
// 使用 PreparedStatement (安全)
String sql = "SELECT * FROM users WHERE name = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, userName); // 将 userName 作为参数设置
// ...
}
配置文件管理
不要将数据库 URL、用户名、密码等敏感信息硬编码在代码中,应该放在外部配置文件(如 application.properties 或 config.properties)中。
config.properties 文件:
db.url=jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC db.user=java_user db.password=password123 db.pool.size=10
然后在 Java 代码中读取这个文件。
异常处理
数据库操作可能会因为网络问题、SQL 语法错误、权限问题等抛出 SQLException,你应该妥善捕获并处理这些异常,例如记录日志,而不是简单地 printStackTrace()。
如何选择?
| 特性 | JDBC 驱动 (传统方式) | 连接池 (如 HikariCP) |
|---|---|---|
| 性能 | 差,频繁创建/销毁连接 | 高,复用连接,性能优异 |
| 资源管理 | 差,容易泄漏 | 好,自动管理连接的生命周期 |
| 适用场景 | 简单的、一次性的脚本或测试 | 所有生产环境、Web 应用、高并发场景 |
| 代码复杂度 | 简单 | 稍复杂,但配置后一劳永逸 |
- 学习和测试时: 可以使用传统的 JDBC 方式,帮助你理解底层原理。
- 任何实际项目(尤其是生产环境): 必须使用连接池,HikariCP 是目前的首选。必须结合
try-with-resources和PreparedStatement来编写健壮、安全、高效的数据库访问代码。
