准备工作
在编写代码之前,您需要完成以下准备工作:

安装 MySQL 数据库
确保您的计算机上已经安装并运行了 MySQL 数据库,如果没有,请从 MySQL 官网 下载并安装。
创建数据库和表
登录到您的 MySQL 服务器(可以使用命令行或如 MySQL Workbench, Navicat 等图形化工具),创建一个示例数据库和一张用于测试的表。
-- 创建一个名为 `jdbc_test` 的数据库
CREATE DATABASE jdbc_test;
-- 使用这个数据库
USE jdbc_test;
-- 创建一张名为 `users` 的表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
age INT
);
-- 插入一些测试数据
INSERT INTO users (name, email, age) VALUES
('Alice', 'alice@example.com', 28),
('Bob', 'bob@example.com', 32),
('Charlie', 'charlie@example.com', 24);
获取数据库连接信息
记下以下信息,后续代码中会用到:
- 主机名: 通常是
localhost(如果数据库在本地运行) - 端口: 默认是
3306 - 数据库名:
jdbc_test - 用户名: 您的 MySQL 用户名 (
root) - 密码: 您的 MySQL 密码
添加 MySQL JDBC 驱动
Java 程序需要通过 JDBC 驱动来与 MySQL 数据库通信,您需要下载 MySQL Connector/J(这是官方的 JDBC 驱动)。

推荐方式:使用 Maven 或 Gradle(现代项目首选)
如果您使用 Maven,在您的 pom.xml 文件中添加以下依赖:
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 建议使用最新稳定版 -->
</dependency>
如果您使用 Gradle,在您的 build.gradle 文件中添加:
implementation 'com.mysql:mysql-connector-j:8.0.33' // 建议使用最新稳定版
手动方式(不推荐,但适用于简单项目)

- 访问 MySQL Connector/J 下载页面。
- 下载 Platform Independent 版本的 ZIP 文件。
- 解压后,找到
mysql-connector-j-<version>.jar文件。 - 在您的 Java IDE(如 IntelliJ IDEA 或 Eclipse)中,将此 JAR 文件添加到项目的类路径(Classpath)中。
第二步:编写 Java 代码
我们将创建一个完整的 Java 类,演示如何执行基本的数据库操作:查询、插入、更新和删除。
这里我们使用 JDBC 4.0+ 的标准方式,它不需要显式地加载驱动类,驱动管理器会自动处理。
完整代码示例
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class MysqlJdbcExample {
// --- 数据库连接信息 ---
// 请根据您的实际情况修改这些值
private static final String DB_URL = "jdbc:mysql://localhost:3306/jdbc_test?useSSL=false&serverTimezone=UTC";
private static final String USER = "root"; // 您的数据库用户名
private static final String PASS = "your_password"; // 您的数据库密码
public static void main(String[] args) {
// 使用 try-with-resources 语句,确保资源在使用后被自动关闭
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS)) {
System.out.println("成功连接到数据库!");
// 1. 查询数据
System.out.println("\n--- 查询所有用户 ---");
selectAllUsers(conn);
// 2. 插入数据
System.out.println("\n--- 插入一个新用户 ---");
insertUser(conn, "David", "david@example.com", 40);
// 再次查询以验证插入
selectAllUsers(conn);
// 3. 更新数据
System.out.println("\n--- 更新用户 'Alice' 的年龄 ---");
updateUserAge(conn, "Alice", 29);
selectAllUsers(conn);
// 4. 删除数据
System.out.println("\n--- 删除用户 'Bob' ---");
deleteUser(conn, "Bob");
selectAllUsers(conn);
} catch (SQLException e) {
System.err.println("数据库连接或操作失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 查询并打印所有用户
*/
private static void selectAllUsers(Connection conn) throws SQLException {
String sql = "SELECT id, name, email, age FROM users";
// Statement 用于执行静态 SQL 语句
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
System.out.println("ID | Name | Email | Age");
System.out.println("------------------------------------------");
while (rs.next()) {
// 通过列名获取数据,更具可读性和健壮性
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
int age = rs.getInt("age");
System.out.printf("%d | %-9s | %-19s | %d%n", id, name, email, age);
}
}
}
/**
* 使用 PreparedStatement 插入新用户(防止 SQL 注入)
*/
private static void insertUser(Connection conn, String name, String email, int age) throws SQLException {
String sql = "INSERT INTO users (name, email, age) VALUES (?, ?, ?)";
// PreparedStatement 用于执行预编译的 SQL 语句,防止 SQL 注入
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置参数 (索引从 1 开始)
pstmt.setString(1, name);
pstmt.setString(2, email);
pstmt.setInt(3, age);
int affectedRows = pstmt.executeUpdate();
System.out.println("成功插入 " + affectedRows + " 行数据。");
}
}
/**
* 更新用户年龄
*/
private static void updateUserAge(Connection conn, String name, int newAge) throws SQLException {
String sql = "UPDATE users SET age = ? WHERE name = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, newAge);
pstmt.setString(2, name);
int affectedRows = pstmt.executeUpdate();
System.out.println("成功更新 " + affectedRows + " 行数据。");
}
}
/**
* 删除用户
*/
private static void deleteUser(Connection conn, String name) throws SQLException {
String sql = "DELETE FROM users WHERE name = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, name);
int affectedRows = pstmt.executeUpdate();
System.out.println("成功删除 " + affectedRows + " 行数据。");
}
}
}
代码详解
-
数据库连接信息:
DB_URL: JDBC URL 格式为jdbc:mysql://[host]:[port]/[database_name]。?useSSL=false: 在本地开发时可以禁用 SSL 以避免警告。&serverTimezone=UTC: 设置服务器时区,避免时区警告。
USER和PASS: 您的 MySQL 用户名和密码。
-
DriverManager.getConnection():- 这是建立数据库连接的核心方法,它接受 URL、用户名和密码作为参数,并返回一个
Connection对象,代表与数据库的会话。
- 这是建立数据库连接的核心方法,它接受 URL、用户名和密码作为参数,并返回一个
-
try-with-resources语句:- 这是 Java 7 引入的一个非常实用的特性,它会自动实现
AutoCloseable接口的资源(如Connection,Statement,ResultSet)在语句块结束时被关闭,无需手动调用close()方法,有效避免了资源泄漏。
- 这是 Java 7 引入的一个非常实用的特性,它会自动实现
-
查询数据 (
selectAllUsers):Statement: 用于执行不带参数的简单 SQL 查询。executeQuery(sql): 执行SELECT查询,返回一个ResultSet对象,该对象包含了查询结果。ResultSet: 一个指向结果集数据行的游标。rs.next()将游标移动到下一行,如果存在下一行则返回true。rs.getXXX(): 从当前行获取列的值,可以使用列名(如rs.getString("name"))或列索引(如rs.getString(2)),推荐使用列名,因为代码更清晰,且当 SQL 查询的列顺序改变时不易出错。
-
增删改数据 (
insertUser,updateUserAge,deleteUser):PreparedStatement: 用于执行带参数的 SQL 语句,它将 SQL 语句预编译,然后通过setXXX()方法设置参数值。- 优点:
- 性能高: 如果同一条 SQL 语句需要多次执行,只需编译一次,效率更高。
- 安全性高: 能有效防止 SQL 注入攻击,因为它会将参数值作为数据处理,而不是 SQL 语句的一部分。
executeUpdate(): 用于执行INSERT,UPDATE,DELETE等会改变数据库数据的 SQL 语句,返回一个整数,表示受影响的行数。
-
异常处理 (
SQLException):- 所有 JDBC 操作都可能抛出
SQLException,必须用try-catch块处理它,以便在发生错误时能够捕获并处理。
- 所有 JDBC 操作都可能抛出
运行结果
在您修改了代码中的数据库连接信息(用户名和密码)后,运行该 MysqlJdbcExample 类,您将看到类似以下的输出:
成功连接到数据库!
--- 查询所有用户 ---
ID | Name | Email | Age
------------------------------------------
1 | Alice | alice@example.com | 28
2 | Bob | bob@example.com | 32
3 | Charlie | charlie@example.com | 24
--- 插入一个新用户 ---
成功插入 1 行数据。
--- 查询所有用户 ---
ID | Name | Email | Age
------------------------------------------
1 | Alice | alice@example.com | 28
2 | Bob | bob@example.com | 32
3 | Charlie | charlie@example.com | 24
4 | David | david@example.com | 40
--- 更新用户 'Alice' 的年龄 ---
成功更新 1 行数据。
--- 查询所有用户 ---
ID | Name | Email | Age
------------------------------------------
1 | Alice | alice@example.com | 29
2 | Bob | bob@example.com | 32
3 | Charlie | charlie@example.com | 24
4 | David | david@example.com | 40
--- 删除用户 'Bob' ---
成功删除 1 行数据。
--- 查询所有用户 ---
ID | Name | Email | Age
------------------------------------------
1 | Alice | alice@example.com | 29
3 | Charlie | charlie@example.com | 24
4 | David | david@example.com | 40
总结与最佳实践
- 总是使用
PreparedStatement: 除非您 100% 确定您的 SQL 语句是静态的且不会受到外部输入的影响,否则永远不要使用Statement。PreparedStatement是更安全、更高效的选择。 - 总是使用
try-with-resources: 这是管理 JDBC 资源(连接、语句、结果集)的现代标准做法,能极大地简化代码并避免资源泄漏。 - 不要硬编码凭证: 在实际生产环境中,不要将数据库用户名和密码直接写在代码里,应该使用配置文件(如
config.properties)、环境变量或专门的密钥管理服务来管理敏感信息。 - 考虑连接池: 对于高并发的应用,频繁地创建和销毁数据库连接是非常消耗资源的,应该使用连接池(如 HikariCP, C3P0, DBCP)来管理和复用数据库连接。
