目录
- 准备工作
- 安装 MySQL 数据库
- 创建数据库和表
- 准备 Java 开发环境
- 核心步骤详解
- 第一步:添加 MySQL 驱动依赖
- 第二步:建立数据库连接
- 第三步:创建
Statement或PreparedStatement - 第四步:执行查询
- 第五步:处理结果集 (
ResultSet) - 第六步:关闭资源
- 完整代码示例
- 示例 1:使用
Statement(不推荐,仅用于理解) - 示例 2:使用
PreparedStatement(推荐,安全高效) - 示例 3:将查询结果封装到 Java 对象 (面向对象方式)
- 示例 1:使用
- 最佳实践与高级技巧
- 必须使用
PreparedStatement:防止 SQL 注入 - 使用
try-with-resources:自动管理资源 - 使用连接池:提高性能
- 处理大数据类型:如
BLOB,CLOB - 事务管理
- 必须使用
- 常见问题与排错
准备工作
a. 安装 MySQL 数据库
确保你的系统上已经安装并运行了 MySQL 数据库,你可以从 MySQL 官网 下载并安装。

b. 创建数据库和表
打开 MySQL 命令行客户端或使用如 Navicat, DBeaver 等图形化工具,执行以下 SQL 语句来创建一个示例数据库和表。
-- 创建一个名为 'testdb' 的数据库
CREATE DATABASE IF NOT EXISTS testdb;
-- 使用这个数据库
USE testdb;
-- 创建一个 'users' 表
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入一些测试数据
INSERT INTO users (username, email, age) VALUES
('zhangsan', 'zhangsan@example.com', 25),
('lisi', 'lisi@example.com', 30),
('wangwu', 'wangwu@example.com', 28);
c. 准备 Java 开发环境
确保你已经安装了 JDK 和一个 IDE(如 IntelliJ IDEA 或 Eclipse)。
核心步骤详解
第一步:添加 MySQL 驱动依赖
Java 程序需要 MySQL 的 JDBC 驱动才能与 MySQL 数据库通信,现在最主流的方式是使用 Maven 或 Gradle 来管理项目依赖。
Maven (pom.xml):
在 pom.xml 文件中添加以下依赖:

<dependencies>
<!-- MySQL Connector/J 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 建议使用最新稳定版 -->
</dependency>
</dependencies>
Gradle (build.gradle):
在 build.gradle 文件中添加:
dependencies {
// MySQL Connector/J 驱动
implementation 'com.mysql:mysql-connector-j:8.0.33' // 建议使用最新稳定版
}
第二步:建立数据库连接
你需要数据库的 URL、用户名和密码来建立连接。
-
URL 格式:
jdbc:mysql://[主机名]:[端口]/[数据库名]?[属性]- 主机名: 通常是
localhost或0.0.1。 - 端口: MySQL 默认端口是
3306。 - 数据库名: 你要连接的数据库,如
testdb。 - 属性:
useSSL=false(用于本地开发,禁用 SSL 加密) 或useSSL=true(生产环境推荐)。serverTimezone=UTC用于解决时区问题。
- 主机名: 通常是
-
示例代码:
(图片来源网络,侵删)String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC"; String username = "root"; // 你的 MySQL 用户名 String password = "your_password"; // 你的 MySQL 密码 Connection connection = null; try { // 加载驱动 (对于新版本驱动,这步通常可以省略) Class.forName("com.mysql.cj.jdbc.Driver"); // 建立连接 connection = DriverManager.getConnection(url, username, password); System.out.println("数据库连接成功!"); } catch (Exception e) { e.printStackTrace(); }
第三步:创建 Statement 或 PreparedStatement
连接建立后,你需要一个对象来执行 SQL 语句。
Statement: 用于执行静态的 SQL 语句。不推荐用于包含用户输入的查询,因为它极易受到 SQL 注入攻击。PreparedStatement: 强烈推荐,它预编译 SQL 语句,并使用 作为占位符,你可以安全地设置参数,有效防止 SQL 注入,并且性能通常更好。
第四步:执行查询
调用 executeQuery() 方法来执行 SELECT 查询,这个方法会返回一个 ResultSet 对象。
String sql = "SELECT id, username, email, age FROM users"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql);
第五步:处理结果集 (ResultSet)
ResultSet 就像一个指向查询结果数据的指针,你需要使用 next() 方法将指针移动到下一行,并使用 getXXX() 方法(如 getString(), getInt())来获取列的值。
while (resultSet.next()) { // 循环遍历每一行
// 通过列名获取数据,更具可读性
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String email = resultSet.getString("email");
int age = resultSet.getInt("age");
// 也可以通过列索引获取 (从1开始)
// int id = resultSet.getInt(1);
System.out.println("ID: " + id + ", 用户名: " + username + ", 邮箱: " + email + ", 年龄: " + age);
}
第六步:关闭资源
为了防止资源泄露(如数据库连接、内存占用),你必须按照创建的逆序关闭所有资源:ResultSet -> Statement -> Connection。
if (resultSet != null) {
try { resultSet.close(); } catch (SQLException e) { /* ... */ }
}
if (statement != null) {
try { statement.close(); } catch (SQLException e) { /* ... */ }
}
if (connection != null) {
try { connection.close(); } catch (SQLException e) { /* ... */ }
}
完整代码示例
示例 2:使用 PreparedStatement (推荐)
这是最常用、最安全的方式。
import java.sql.*;
public class JdbcPreparedStatementExample {
// 数据库连接信息
private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
public static void main(String[] args) {
// 使用 try-with-resources 自动管理资源,无需手动关闭
try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {
System.out.println("数据库连接成功!");
// 1. 准备 SQL 语句,使用 ? 作为占位符
String sql = "SELECT id, username, email, age FROM users WHERE age > ?";
// 2. 创建 PreparedStatement 对象
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
// 3. 设置参数 (index 从 1 开始)
preparedStatement.setInt(1, 26); // 设置第一个 ? 为 26
// 4. 执行查询
try (ResultSet resultSet = preparedStatement.executeQuery()) {
// 5. 处理结果集
System.out.println("年龄大于 26 的用户:");
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String email = resultSet.getString("email");
int age = resultSet.getInt("age");
System.out.printf("ID: %d, 用户名: %s, 邮箱: %s, 年龄: %d%n", id, username, email, age);
}
}
}
} catch (SQLException e) {
System.err.println("数据库操作出错!");
e.printStackTrace();
}
}
}
示例 3:将查询结果封装到 Java 对象 (面向对象方式)
在实际项目中,我们通常会将数据库的一行数据映射到一个 Java 对象中,这样更符合面向对象的思想。
创建 User 实体类:
// User.java
public class User {
private int id;
private String username;
private String email;
private int age;
// 构造方法、Getter 和 Setter
public User() {}
public User(int id, String username, String email, int age) {
this.id = id;
this.username = username;
this.email = email;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
// 省略 Getter 和 Setter...
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
修改查询代码以返回 List<User>:
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class JdbcObjectMappingExample {
private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
public static void main(String[] args) {
String sql = "SELECT id, username, email, age FROM users";
List<User> users = new ArrayList<>();
try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
// 从结果集中取出数据,创建 User 对象
User user = new User();
user.setId(resultSet.getInt("id"));
user.setUsername(resultSet.getString("username"));
user.setEmail(resultSet.getString("email"));
user.setAge(resultSet.getInt("age"));
// 将 User 对象添加到 List 中
users.add(user);
}
} catch (SQLException e) {
e.printStackTrace();
}
// 打印结果
System.out.println("所有用户:");
for (User user : users) {
System.out.println(user);
}
}
}
最佳实践与高级技巧
a. 必须使用 PreparedStatement
永远不要使用 Statement 来拼接 SQL 字符串来处理用户输入。PreparedStatement 通过预编译和参数绑定,从根本上杜绝了 SQL 注入的风险。
b. 使用 try-with-resources
从 Java 7 开始,try-with-resources 语句可以自动实现 AutoCloseable 接口的资源关闭,强烈推荐使用它,代码更简洁,也更能保证资源被正确关闭,避免泄露。
// 自动关闭 Connection, PreparedStatement, ResultSet
try (Connection con = ...;
PreparedStatement ps = con.prepareStatement(...);
ResultSet rs = ps.executeQuery()) {
// ... do work ...
} // con, ps, rs 在这里会自动关闭
c. 使用连接池
每次创建和销毁数据库连接都是非常消耗性能的操作,在高并发应用中,必须使用连接池来复用连接。
-
常用连接池: HikariCP (性能极佳,是目前的事实标准), Druid (阿里巴巴出品,功能强大,带有监控), C3P0。
-
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; HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb"); config.setUsername("root"); config.setPassword("your_password"); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); HikariDataSource dataSource = new HikariDataSource(config); // 从连接池获取连接 try (Connection connection = dataSource.getConnection()) { // 使用 connection 进行数据库操作... }
d. 处理大数据类型
对于 BLOB (二进制数据,如图片) 或 CLOB (文本数据),需要使用 getInputStream() 和 setBinaryStream() / setCharacterStream() 来流式处理,避免内存溢出。
e. 事务管理
默认情况下,每个 SQL 语句都是一个独立的事务,你可以手动控制事务的提交和回滚。
Connection connection = null;
try {
connection = dataSource.getConnection();
// 关闭自动提交,开启事务
connection.setAutoCommit(false);
// 执行多个 SQL 语句
// statement1.executeUpdate(...);
// statement2.executeUpdate(...);
// 所有语句执行成功,提交事务
connection.commit();
System.out.println("事务提交成功!");
} catch (SQLException e) {
// 发生异常,回滚事务
if (connection != null) {
try {
connection.rollback();
System.out.println("事务已回滚!");
} catch (SQLException ex) {
ex.printStackTrace();
}
}
e.printStackTrace();
} finally {
if (connection != null) {
try {
// 恢复自动提交模式
connection.setAutoCommit(true);
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
常见问题与排错
-
No suitable driver found for jdbc:mysql://...- 原因: MySQL 驱动依赖没有添加到项目中,或者 IDE 没有正确加载依赖。
- 解决: 确保
pom.xml或build.gradle中的依赖已正确配置,并刷新 Maven/Gradle 项目。
-
Access denied for user 'root'@'localhost'- 原因: 数据库用户名或密码错误。
- 解决: 检查你的 Java 代码中
USER和PASSWORD是否与 MySQL 中的用户信息匹配。
-
Unknown database 'testdb'- 原因: 连接 URL 中的数据库名不存在。
- 解决: 检查数据库名拼写是否正确,或者先在 MySQL 中创建该数据库。
-
Communications link failure- 原因: MySQL 服务未启动,或者网络不通(如防火墙阻止了 3306 端口)。
- 解决: 确保 MySQL 服务正在运行,并且可以从你的 Java 应用程序所在机器访问到 MySQL 服务器的 3306 端口。
希望这份详细的指南能帮助你顺利地在 Java 中使用 MySQL 进行数据库查询!
