杰瑞科技汇

Java如何向MySQL插入数据?

目录

  1. 准备工作
    • 安装 MySQL 数据库
    • 创建数据库和表
    • 添加 MySQL JDBC 驱动依赖
  2. 核心代码步骤
    • 加载 JDBC 驱动
    • 建立数据库连接
    • 创建 PreparedStatement (防止 SQL 注入)
    • 设置 SQL 语句参数
    • 执行更新操作
    • 处理结果 (获取影响的行数)
    • 关闭资源
  3. 完整代码示例
    • 单条数据插入
    • 批量数据插入 (高效)
  4. 最佳实践与注意事项
    • 使用 try-with-resources 自动关闭资源
    • 使用 PreparedStatement 防止 SQL 注入
    • 使用连接池
    • 事务管理

准备工作

a. 安装 MySQL 数据库

确保你已经安装并运行了 MySQL 数据库,如果没有,请从 MySQL 官网 下载并安装。

b. 创建数据库和表

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

-- 创建一个名为 `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_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 创建时间,默认为当前时间
);
-- 查看表结构
DESCRIBE users;

c. 添加 MySQL JDBC 驱动依赖

你的 Java 项目需要知道如何与 MySQL 通信,这就需要 MySQL 的 JDBC 驱动程序,根据你的项目类型,添加方式不同。

Maven (推荐) 在你的 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 文件中添加:

dependencies {
    // MySQL Connector/J
    implementation 'com.mysql:mysql-connector-j:8.0.33' // 建议使用较新的稳定版本
}

手动下载 JAR 包 如果你不使用构建工具,可以从 Maven 中央仓库 下载 mysql-connector-j-x.x.x.jar 文件,并将其添加到你的项目的类路径中。


核心代码步骤

以下是使用 JDBC 插入数据的标准流程。

a. 加载 JDBC 驱动

对于较新的 JDBC 驱动(4.0+),这一步通常是可选的,因为驱动会自动加载,但显式加载是个好习惯。

Class.forName("com.mysql.cj.jdbc.Driver");

b. 建立数据库连接

使用 DriverManagergetConnection() 方法来建立与数据库的连接,你需要提供数据库的 URL、用户名和密码。

  • URL 格式: jdbc:mysql://[主机名]:[端口号]/[数据库名]?[属性]
    • 主机名: 通常是 localhost0.0.1
    • 端口号: MySQL 默认是 3306
    • 属性: useSSL=false (开发环境可以禁用SSL), serverTimezone=UTC (指定时区)
String url = "jdbc:mysql://localhost:3306/java_test?useSSL=false&serverTimezone=UTC";
String username = "root"; // 你的 MySQL 用户名
String password = "your_password"; // 你的 MySQL 密码
Connection conn = DriverManager.getConnection(url, username, password);

c. 创建 PreparedStatement

强烈推荐使用 PreparedStatement 而不是 StatementPreparedStatement 可以预编译 SQL 语句,并且使用 作为占位符,能有效防止 SQL 注入攻击,并且性能更好。

String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);

d. 设置 SQL 语句参数

使用 setXxx() 方法(如 setString(), setInt())来为 占位符设置值,参数的索引从 1 开始。

pstmt.setString(1, "john_doe"); // 设置第一个 ? 为 'john_doe'
pstmt.setString(2, "password123"); // 设置第二个 ? 为 'password123'
pstmt.setString(3, "john.doe@example.com"); // 设置第三个 ? 为 'john.doe@example.com'

e. 执行更新操作

对于 INSERT, UPDATE, DELETE 这类不返回结果集的 SQL 语句,使用 executeUpdate() 方法,它会返回一个整数,表示受影响的行数。

int affectedRows = pstmt.executeUpdate();

f. 处理结果

检查 affectedRows 来确认操作是否成功。

if (affectedRows > 0) {
    System.out.println("数据插入成功!影响了 " + affectedRows + " 行。");
} else {
    System.out.println("数据插入失败。");
}

g. 关闭资源

为了防止资源泄漏,必须关闭所有打开的 JDBC 对象,顺序是:后打开的先关闭 (pstmt -> conn)。

pstmt.close();
conn.close();

完整代码示例

示例 1: 单条数据插入

这是一个完整的、可运行的示例,遵循了上述所有步骤。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class InsertSingleUser {
    // 数据库连接信息
    private static final String DB_URL = "jdbc:mysql://localhost:3306/java_test?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASS = "your_password";
    public static void main(String[] args) {
        // SQL 插入语句,使用 ? 作为占位符
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        // 使用 try-with-resources 自动关闭资源
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数
            pstmt.setString(1, "jane_doe");
            pstmt.setString(2, "securepass456");
            pstmt.setString(3, "jane.doe@example.com");
            // 执行更新
            int affectedRows = pstmt.executeUpdate();
            // 检查结果
            if (affectedRows > 0) {
                System.out.println("新用户 'jane_doe' 创建成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

示例 2: 批量数据插入 (高效)

当需要插入大量数据时,一条一条插入效率很低,JDBC 提供了批量操作功能,可以大大提高性能。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class BatchInsertUsers {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/java_test?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASS = "your_password";
    public static void main(String[] args) {
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 关闭自动提交,以便进行事务管理
            conn.setAutoCommit(false);
            // 添加要执行的 SQL 语句到批处理中
            for (int i = 1; i <= 10; i++) {
                pstmt.setString(1, "user_" + i);
                pstmt.setString(2, "password_" + i);
                pstmt.setString(3, "user_" + i + "@example.com");
                pstmt.addBatch(); // 将参数化的语句添加到批处理中
            }
            // 执行批处理
            int[] results = pstmt.executeBatch();
            // 提交事务
            conn.commit();
            System.out.println("批量插入完成,共插入了 " + results.length + " 条记录。");
        } catch (SQLException e) {
            e.printStackTrace();
            // 如果发生错误,回滚事务
            try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS)) {
                if (conn != null) {
                    conn.rollback();
                    System.err.println("发生错误,已回滚事务。");
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

最佳实践与注意事项

a. 使用 try-with-resources (Java 7+)

如示例中所示,try-with-resources 语句可以自动实现 AutoCloseable 接口的对象(如 Connection, PreparedStatement),当代码块执行完毕后,它们会自动关闭,即使发生异常也能确保资源被释放,是防止资源泄漏的最佳方式。

b. 永远使用 PreparedStatement 来防止 SQL 注入

拼接 SQL 字符串来构建查询是极其危险的,这会让你的应用极易受到 SQL 注入攻击。 错误示范:

// 危险!不要这样做!
String username = "admin' OR '1'='1";
String sql = "SELECT * FROM users WHERE username = '" + username + "'";

攻击者可以通过输入特殊的字符串来操纵 SQL 逻辑,从而绕过认证或窃取数据。PreparedStatement 会将数据和 SQL 语句分开处理,从根本上杜绝了这种风险。

c. 使用连接池

每次执行 SQL 操作都创建一个新的连接是非常消耗资源的,在高并发的应用中,性能会急剧下降,解决方案是使用连接池,如 HikariCP (目前性能最好的连接池)、Apache DBCPC3P0

连接池会在应用启动时创建一组数据库连接,并缓存起来,当需要时,从池中获取一个用完后再放回池中,避免了频繁创建和销毁连接的开销。

使用 HikariCP 的示例:

  1. 添加依赖 (pom.xml):

    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version>
    </dependency>
  2. 代码中创建和使用数据源:

    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    // ... 在类加载时或应用启动时初始化数据源
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl("jdbc:mysql://localhost:3306/java_test?useSSL=false&serverTimezone=UTC");
    config.setUsername("root");
    config.setPassword("your_password");
    HikariDataSource ds = new HikariDataSource(config);
    // ... 在需要连接时
    try (Connection conn = ds.getConnection()) {
        // 使用 conn 进行数据库操作
    }

d. 事务管理

默认情况下,每条 SQL 语句都是一个独立的事务,对于需要多个步骤作为一个整体执行的业务逻辑(转账操作:从 A 账户扣款,然后向 B 账户存款),你需要手动管理事务。

  • conn.setAutoCommit(false); // 关闭自动提交
  • conn.commit(); // 手动提交事务
  • conn.rollback(); // 发生错误时回滚事务

批量插入示例所示,将多个 addBatch() 操作放在一个事务中,可以保证它们要么全部成功,要么全部失败,保证了数据的一致性。

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