杰瑞科技汇

Java如何实现MySQL的增删改查?

  1. 环境准备:安装必要的软件和库。
  2. JDBC 核心概念:了解几个关键的类和接口。
  3. 项目配置:如何在 Java 项目中引入 MySQL 驱动。
  4. CRUD 完整代码示例:一个完整的、可运行的 Java 类,包含所有操作。
  5. 最佳实践:使用 PreparedStatementtry-with-resources
  6. 进阶:使用连接池。

环境准备

在开始之前,请确保你已经安装并配置好了以下环境:

Java如何实现MySQL的增删改查?-图1
(图片来源网络,侵删)
  • Java Development Kit (JDK): 版本 8 或更高。
  • MySQL Server: 已安装并正在运行,并且创建了一个数据库。
  • IDE: 如 IntelliJ IDEA, Eclipse 或 VS Code。

数据库准备

让我们创建一个简单的数据库和一张 users 表用于演示。

-- 1. 创建一个数据库
CREATE DATABASE my_jdbc_db;
-- 2. 使用该数据库
USE my_jdbc_db;
-- 3. 创建一个用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 4. 插入一些初始数据
INSERT INTO users (username, password, email) VALUES ('alice', '123456', 'alice@example.com');
INSERT INTO users (username, password, email) VALUES ('bob', 'bobpass', 'bob@example.com');

JDBC 核心概念

JDBC 是 Java 访问数据库的 API,它定义了一套接口,具体的实现由数据库厂商(如 Oracle, MySQL)提供,我们称之为驱动

你需要了解以下几个核心类/接口:

Java如何实现MySQL的增删改查?-图2
(图片来源网络,侵删)
  • DriverManager: 管理数据库驱动程序,它的主要作用是建立与数据库的连接。
  • Connection: 代表与数据库的连接,所有 SQL 操作都通过这个连接对象执行。
  • Statement: 用于执行静态 SQL 语句并返回它所生成结果的对象,我们通常不直接使用它,因为它有 SQL 注入的风险。
  • PreparedStatement: Statement 的子接口,用于执行预编译的 SQL 语句。强烈推荐使用,因为它可以防止 SQL 注入,并且性能更好。
  • ResultSet: 代表 SQL 查询的结果集,它是一个指向结果集数据行的游标。

项目配置 (引入 MySQL 驱动)

你需要将 MySQL 的 JDBC 驱动程序(一个 .jar 文件)添加到你的 Java 项目中。

使用 Maven (推荐)

如果你使用 Maven,只需在 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- MySQL Connector/J 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 建议使用最新稳定版 -->
    </dependency>
</dependencies>

Maven 会自动下载并管理这个依赖。

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

手动添加 JAR

如果你不使用 Maven,可以:

  1. Maven 中央仓库 下载 mysql-connector-j-x.x.xx.jar 文件。
  2. 在你的 IDE 中,将这个 JAR 文件添加到项目的库(Libraries)或构建路径(Build Path)中。

CRUD 完整代码示例

下面是一个完整的 Java 类,演示了如何连接数据库并进行增、删、改、查操作。

我们将使用 try-with-resources 语句,它可以自动关闭实现了 AutoCloseable 接口的对象(如 Connection, PreparedStatement, ResultSet),避免资源泄漏。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.LocalDateTime;
public class MysqlCrudExample {
    // --- 数据库连接信息 ---
    // 注意:如果使用 MySQL 8.0+,驱动类名是 com.mysql.cj.jdbc.Driver
    private static final String DB_URL = "jdbc:mysql://localhost:3306/my_jdbc_db?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root"; // 你的数据库用户名
    private static final String PASS = "your_password"; // 你的数据库密码
    public static void main(String[] args) {
        // 为了演示,我们把所有操作放在 main 方法里
        // 实际项目中,这些操作会分布在不同层(DAO层, Service层等)
        System.out.println("===== 1. 查询所有用户 (SELECT) =====");
        selectAllUsers();
        System.out.println("\n===== 2. 创建新用户 (INSERT) =====");
        // 假设新用户的ID是自增的,我们不需要在SQL中指定
        int newUserId = insertUser("charlie", "charlie_pass", "charlie@example.com");
        System.out.println("成功创建新用户,ID为: " + newUserId);
        System.out.println("\n===== 3. 更新用户信息 (UPDATE) =====");
        boolean updateResult = updateUserEmail(newUserId, "charlie.new@example.com");
        System.out.println("更新用户 " + newUserId + " 的邮箱结果: " + (updateResult ? "成功" : "失败"));
        System.out.println("\n===== 4. 查询单个用户 (SELECT by ID) =====");
        User user = selectUserById(newUserId);
        if (user != null) {
            System.out.println("查找到用户: " + user);
        }
        System.out.println("\n===== 5. 删除用户 (DELETE) =====");
        boolean deleteResult = deleteUserById(newUserId);
        System.out.println("删除用户 " + newUserId + " 结果: " + (deleteResult ? "成功" : "失败"));
        System.out.println("\n===== 6. 再次查询所有用户,确认删除 =====");
        selectAllUsers();
    }
    // --- 增 ---
    // 返回新插入用户的ID
    public static int insertUser(String username, String password, String email) {
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        // 使用 Statement.RETURN_GENERATED_KEYS 来获取自增主键
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            pstmt.setString(3, email);
            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                // 获取生成的键
                try (ResultSet rs = pstmt.getGeneratedKeys()) {
                    if (rs.next()) {
                        return rs.getInt(1); // 返回新用户的ID
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return -1; // 插入失败
    }
    // --- 删 ---
    public static boolean deleteUserById(int id) {
        String sql = "DELETE FROM users WHERE id = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, id);
            int affectedRows = pstmt.executeUpdate();
            return affectedRows > 0; // 如果影响行数大于0,则表示删除成功
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }
    // --- 改 ---
    public static boolean updateUserEmail(int id, String newEmail) {
        String sql = "UPDATE users SET email = ? WHERE id = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, newEmail);
            pstmt.setInt(2, id);
            int affectedRows = pstmt.executeUpdate();
            return affectedRows > 0; // 如果影响行数大于0,则表示更新成功
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }
    // --- 查 ---
    public static void selectAllUsers() {
        String sql = "SELECT id, username, password, email, created_at 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 At");
            System.out.println("--------------------------------------------------");
            while (rs.next()) {
                // 通过列名获取数据,可读性更好,且不易受列顺序影响
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String email = rs.getString("email");
                Timestamp createdAt = rs.getTimestamp("created_at");
                System.out.printf("%d\t%s\t\t%s\t%s\n", id, username, email, createdAt);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // --- 查 (单个) ---
    public static User selectUserById(int id) {
        String sql = "SELECT id, username, password, email, created_at FROM users WHERE id = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, id);
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    User user = new User();
                    user.setId(rs.getInt("id"));
                    user.setUsername(rs.getString("username"));
                    user.setPassword(rs.getString("password"));
                    user.setEmail(rs.getString("email"));
                    user.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
                    return user;
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null; // 未找到用户
    }
}
// 一个简单的POJO类,用于映射用户数据
class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private LocalDateTime createdAt;
    // Getters and Setters
    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 getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", createdAt=" + createdAt +
                '}';
    }
}

最佳实践

在上面的代码中,我们已经遵循了几个最佳实践:

  1. 使用 PreparedStatement 而不是 Statement

    • 防止 SQL 注入PreparedStatement 会对输入参数进行转义,恶意输入不会被当作 SQL 代码执行。
    • 性能更优:数据库可以对预编译的 SQL 语句进行缓存和优化。
    • 代码更清晰:使用 作为占位符,使得 SQL 语句和参数分离,易于阅读和维护。
  2. 使用 try-with-resources

    • 这是 Java 7 引入的一个语法糖,用于自动管理资源。
    • 任何实现了 AutoCloseable 接口的资源(Connection, Statement, ResultSet)都可以在 try 语句中声明。
    • try 块执行完毕后,无论是否发生异常,这些资源都会被自动关闭,无需手动调用 close() 方法,极大地简化了代码并避免了资源泄漏。
  3. 使用列名访问 ResultSet

    • rs.getString("username") 中,我们使用列名而不是列索引(如 rs.getString(2))。
    • 优点:代码可读性更强,并且当数据库表结构(列的顺序)发生变化时,你的 Java 代码不会受影响,更加健壮。

进阶:使用连接池

每次执行 SQL 操作都创建一个新的 Connection 是非常消耗资源的,在高并发的应用中,性能会急剧下降。

解决方案是使用数据库连接池,连接池在应用启动时预先创建一定数量的 Connection 对象,并将它们存放在一个池中,当需要连接时,从池中获取一个用完后,再归还给池,而不是直接关闭。

常用的连接池库

  • HikariCP: 目前性能最好的连接池,是 Spring Boot 2.x 的默认选择。
  • Apache DBCP
  • C3P0

使用 HikariCP 的示例

pom.xml 中添加 HikariCP 依赖:

<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.SQLException;
public class DataSourceUtil {
    private static HikariDataSource dataSource;
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/my_jdbc_db?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)
        config.setIdleTimeout(600000);      // 空闲连接超时时间 (ms)
        config.setMaxLifetime(1800000);     // 连接最大存活时间 (ms)
        dataSource = new HikariDataSource(config);
    }
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

你可以修改之前的代码,使用 DataSourceUtil.getConnection() 来获取连接,而不再是 DriverManager.getConnection(),这样可以显著提高应用的性能和稳定性。

操作 SQL 关键字 Java 核心步骤
INSERT Connection -> PreparedStatement -> pstmt.executeUpdate() -> pstmt.getGeneratedKeys()
DELETE Connection -> PreparedStatement -> pstmt.executeUpdate()
UPDATE Connection -> PreparedStatement -> pstmt.executeUpdate()
SELECT Connection -> PreparedStatement -> pstmt.executeQuery() -> 遍历 ResultSet

掌握这些基础后,你就可以开始在 Java 应用中与 MySQL 数据库进行交互了,对于更复杂的项目,可以考虑学习 MyBatis 或 JPA (如 Hibernate) 等 ORM 框架,它们能进一步简化数据库操作。

分享:
扫描分享到社交APP
上一篇
下一篇