杰瑞科技汇

Java MySQL增删改查如何实现?

核心概念

  1. JDBC (Java Database Connectivity): Java 提供的一套标准 API,用于在 Java 程序中执行 SQL 语句,它定义了一组接口和类,让 Java 代码可以与各种数据库进行交互。
  2. 驱动程序: 每个数据库厂商(如 MySQL, Oracle)都会提供自己的 JDBC 实现,称为“驱动程序”,我们需要将这个驱动程序的 JAR 包引入到我们的 Java 项目中。
  3. 连接: 在 Java 程序和数据库之间建立一个通信通道。
  4. Statement / PreparedStatement: 用于向数据库发送 SQL 语句的对象。
    • Statement: 用于执行静态的 SQL 语句。
    • PreparedStatement: 强烈推荐使用,它用于执行预编译的 SQL 语句,可以防止 SQL 注入攻击,并且对于重复执行的 SQL 效率更高。
  5. ResultSet: 当执行查询语句时,数据库返回的结果集,它就像一个指向查询结果的指针。

准备工作

在开始编码之前,请确保你已经完成了以下准备工作:

Java MySQL增删改查如何实现?-图1
(图片来源网络,侵删)

创建 MySQL 数据库和表

打开你的 MySQL 客户端(如 MySQL Workbench, Navicat 或命令行),执行以下 SQL 语句来创建一个数据库和一张用于演示的 users 表。

-- 创建一个名为 `java_test` 的数据库
CREATE DATABASE IF NOT EXISTS java_test;
-- 使用该数据库
USE java_test;
-- 创建一个 `users` 表
CREATE TABLE IF NOT EXISTS users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入一些初始数据
INSERT INTO users (username, password, email) VALUES
('alice', '123456', 'alice@example.com'),
('bob', 'bobpass', 'bob@example.com');

添加 MySQL JDBC 驱动到你的项目

你需要下载 MySQL 的 JDBC 驱动程序 JAR 包,最简单的方式是使用构建工具(Maven 或 Gradle)。

使用 Maven (推荐)

在你的 pom.xml 文件中添加以下依赖:

Java MySQL增删改查如何实现?-图2
(图片来源网络,侵删)
<dependencies>
    <!-- MySQL Connector/J -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 建议使用最新稳定版 -->
    </dependency>
</dependencies>

手动下载

如果你不使用 Maven,可以访问 MySQL Connector/J 下载页面 下载 JAR 包,并将其添加到你的项目的类路径中。


完整代码示例

下面是一个完整的、结构化的 Java 类,它封装了所有增删改查操作,我们将使用 PreparedStatement 来确保代码的安全性和可维护性。

JDBCDemo.java

Java MySQL增删改查如何实现?-图3
(图片来源网络,侵删)
import java.sql.*;
public class JDBCDemo {
    // --- 数据库连接信息 ---
    // 注意:如果你的 MySQL 版本 >= 8.0,驱动类名和 URL 可能需要调整
    // 驱动类名: com.mysql.cj.jdbc.Driver
    // URL: jdbc:mysql://localhost:3306/java_test?useSSL=false&serverTimezone=UTC
    private static final String DB_URL = "jdbc:mysql://localhost:3306/java_test";
    private static final String USER = "root"; // 你的数据库用户名
    private static final String PASS = "your_password"; // 你的数据库密码
    public static void main(String[] args) {
        // 1. 查询所有用户
        System.out.println("--- 查询所有用户 ---");
        selectAllUsers();
        // 2. 添加一个新用户
        System.out.println("\n--- 添加一个新用户 'charlie' ---");
        addUser("charlie", "charliepass", "charlie@example.com");
        selectAllUsers(); // 再次查询以验证
        // 3. 更新一个用户的信息
        System.out.println("\n--- 更新用户 'alice' 的邮箱 ---");
        updateUserEmail("alice", "alice_new@example.com");
        selectAllUsers(); // 再次查询以验证
        // 4. 删除一个用户
        System.out.println("\n--- 删除用户 'bob' ---");
        deleteUser("bob");
        selectAllUsers(); // 再次查询以验证
    }
    /**
     * 查询所有用户
     */
    public static void selectAllUsers() {
        String sql = "SELECT id, username, password, email, created_time FROM users";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            System.out.println("ID\tUsername\tEmail\t\tCreated Time");
            System.out.println("--------------------------------------------------");
            while (rs.next()) {
                // 通过列名获取数据,更安全且可读性更好
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String email = rs.getString("email");
                Timestamp createdTime = rs.getTimestamp("created_time");
                System.out.printf("%d\t%s\t\t%s\t%s\n", id, username, email, createdTime);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 添加一个新用户
     */
    public static void addUser(String username, String password, String email) {
        // 使用 ? 作为占位符,防止 SQL 注入
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             // 使用 PreparedStatement
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数,索引从 1 开始
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            pstmt.setString(3, email);
            // executeUpdate() 用于执行 INSERT, UPDATE, DELETE 等语句
            // 返回受影响的行数
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("用户 '" + username + "' 添加成功!");
            } else {
                System.out.println("用户添加失败。");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 根据用户名更新用户的邮箱
     */
    public static void updateUserEmail(String username, String newEmail) {
        String sql = "UPDATE users SET email = ? WHERE username = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, newEmail);
            pstmt.setString(2, username);
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("用户 '" + username + "' 的邮箱已更新为 '" + newEmail + "'。");
            } else {
                System.out.println("未找到用户 '" + username + "',更新失败。");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 根据用户名删除用户
     */
    public static void deleteUser(String username) {
        String sql = "DELETE FROM users WHERE username = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, username);
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                System.out.println("用户 '" + username + "' 已被删除。");
            } else {
                System.out.println("未找到用户 '" + username + "',删除失败。");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

代码解析

连接数据库 (DriverManager.getConnection)

这是所有操作的第一步,它使用数据库 URL、用户名和密码来建立与数据库的连接。

Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);

注意: 连接是有限的资源,用完后必须关闭,我们使用 try-with-resources 语句(try (Connection conn = ...))可以自动关闭连接,非常方便。

增、删、改 (PreparedStatement.executeUpdate)

这三种操作的结构非常相似,都使用 PreparedStatement

  • SQL 语句: 使用 作为参数占位符。
    String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
  • 创建 PreparedStatement:
    PreparedStatement pstmt = conn.prepareStatement(sql);
  • 设置参数: pstmt.setXxx(index, value) 方法用于将 替换为实际的值。
    • index: 参数的位置,从 1 开始。
    • value: 要设置的值。
    • setString, setInt, setDate 等:根据值的类型选择对应的方法。
      pstmt.setString(1, username);
      pstmt.setString(2, password);
      pstmt.setString(3, email);
  • 执行更新: pstmt.executeUpdate() 会执行 SQL 语句,并返回一个整数,表示受影响的行数。
    int affectedRows = pstmt.executeUpdate();

查 (PreparedStatement.executeQuery)

查询操作与增删改略有不同,因为它需要返回一个结果集。

  • SQL 语句: 可以是静态的,也可以使用 作为条件。

    String sql = "SELECT id, username, email FROM users WHERE username = ?";
  • 创建 PreparedStatement 并设置参数: 这一步和增删改一样。

  • 执行查询: pstmt.executeQuery() 会执行 SQL 语句,并返回一个 ResultSet 对象。

    ResultSet rs = pstmt.executeQuery();
  • 遍历结果集: rs.next() 将光标从当前位置向下移动一行,如果下一行存在,则返回 true,否则返回 false,通常使用 while 循环来遍历所有行。

    while (rs.next()) {
        // 通过列名获取数据,推荐使用这种方式,因为它不依赖列的顺序
        int id = rs.getInt("id");
        String username = rs.getString("username");
        String email = rs.getString("email");
        // 也可以通过列的索引获取数据(从1开始)
        // int id = rs.getInt(1);
    }

最佳实践

  1. 使用 PreparedStatement: 始终优先使用 PreparedStatement,而不是 Statement,它可以有效防止 SQL 注入,并且对于需要多次执行的 SQL,性能更好。
  2. 使用 try-with-resources: 所有实现了 AutoCloseable 接口的资源(如 Connection, Statement, ResultSet)都应该在 try-with-resources 语句中声明,以确保它们在使用完毕后能被自动关闭,避免资源泄漏。
  3. 使用连接池: 在实际应用中,频繁地创建和销毁数据库连接是非常消耗资源的,应该使用数据库连接池(如 HikariCP, Druid, C3P0)来管理连接,连接池可以复用连接,大大提高性能。
  4. 将配置信息外化: 不要将数据库的用户名、密码等敏感信息硬编码在代码中,应该放在配置文件(如 config.properties, application.yml)中,然后在运行时读取。
  5. 处理异常: 捕获 SQLException 并进行适当的处理(如打印日志、返回错误信息给用户),而不是简单地忽略它。

针对 MySQL 8.0+ 的注意事项

如果你使用的是 MySQL 8.0 或更高版本,驱动类名和连接 URL 可能需要调整:

  • 驱动类名: com.mysql.jdbc.Driver 已被弃用,应使用 com.mysql.cj.jdbc.Driver
  • 连接 URL: 必须指定时区,建议添加 serverTimezone=UTC,如果不需要 SSL,可以添加 useSSL=false

修改后的连接信息如下:

// 驱动类名
// Class.forName("com.mysql.cj.jdbc.Driver"); // 在旧版JDBC中需要手动加载,新版JDBC驱动会自动加载
// 连接 URL
private static final String DB_URL = "jdbc:mysql://localhost:3306/java_test?useSSL=false&serverTimezone=UTC";
分享:
扫描分享到社交APP
上一篇
下一篇