当前位置: 首页 > news >正文

使用 JDBC 插入数据并获取自动生成的主键(如 MySQL 的 AUTO_INCREMENT 或 Oracle 的序列) 的完整示例代码,包含详细注释

以下是使用 JDBC 插入数据并获取自动生成的主键(如 MySQL 的 AUTO_INCREMENT 或 Oracle 的序列) 的完整示例代码,包含详细注释:


import java.sql.*;

public class GeneratedKeysExample {
    // 数据库连接参数
    private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";
    private static final String USER = "root";
    private static final String PASSWORD = "your_password";

    public static void main(String[] args) {
        Connection conn = null;
        try {
            // 1. 加载数据库驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2. 获取数据库连接
            conn = DriverManager.getConnection(URL, USER, PASSWORD);

            // 3. 定义插入语句(包含自增主键)
            String sql = "INSERT INTO users (name, email) VALUES (?, ?)";

            // 4. 创建 PreparedStatement 并启用返回生成的键
            try (PreparedStatement pstmt = conn.prepareStatement(
                    sql, 
                    Statement.RETURN_GENERATED_KEYS // 关键:启用生成键的返回
            )) {

                // 5. 设置参数
                pstmt.setString(1, "Alice");
                pstmt.setString(2, "alice@example.com");

                // 6. 执行插入操作
                int affectedRows = pstmt.executeUpdate();
                System.out.println("插入成功,影响行数:" + affectedRows);

                // 7. 获取生成的主键
                try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                    if (generatedKeys.next()) {
                        long userId = generatedKeys.getLong(1); // 获取第一列(主键)
                        System.out.println("生成的用户ID:" + userId);
                    } else {
                        throw new SQLException("创建用户时未获取到主键!");
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            System.out.println("JDBC驱动未找到!");
            e.printStackTrace();
        } catch (SQLException e) {
            System.out.println("数据库操作失败!");
            e.printStackTrace();
        } finally {
            // 8. 关闭连接
            try {
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

代码说明

1. 核心步骤
  1. 启用生成键返回
    prepareStatement() 中传入 Statement.RETURN_GENERATED_KEYS,告知 JDBC 需要返回生成的键。

  2. 执行插入并获取键

    • executeUpdate() 执行插入操作。
    • getGeneratedKeys() 返回包含生成键的 ResultSet
  3. 处理结果集

    • generatedKeys.next() 移动到第一条记录(假设每次插入一条)。
    • getLong(1) 获取第一列(主键列)的值。

2. 数据库表结构(MySQL 示例)
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY, -- 自增主键
    name VARCHAR(50),
    email VARCHAR(100)
);

关键注意事项

  1. 数据库支持

    • MySQL:使用 AUTO_INCREMENT 主键。
    • Oracle:需指定 RETURNING 子句或使用序列(代码需调整)。
    • PostgreSQL:支持 RETURNING 子句,但需调整 SQL 语法。
  2. 多行插入
    如果插入多行,getGeneratedKeys() 返回所有生成的键,需遍历 ResultSet

  3. 列索引
    generatedKeys.getLong(1) 中的 1 表示主键是结果集的第一列。若表有多个生成列,需根据列顺序调整。


扩展场景:Oracle 示例

Oracle 需要使用 RETURNING 子句和序列:

// Oracle 示例代码片段
String sql = "INSERT INTO users (id, name, email) " +
             "VALUES (user_seq.NEXTVAL, ?, ?) " +
             "RETURNING id INTO ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, "Alice");
    pstmt.setString(2, "alice@example.com");
    pstmt.registerOutParameter(3, OracleTypes.NUMBER); // 注册输出参数

    int rows = pstmt.executeUpdate();
    long userId = pstmt.getLong(3); // 通过输出参数获取主键
}

常见问题

Q1:为什么获取不到生成的键?
  • 原因:未在 prepareStatement() 中启用 RETURN_GENERATED_KEYS
  • 解决:确保代码中包含 Statement.RETURN_GENERATED_KEYS
Q2:如何处理批量插入的生成键?
// 批量插入示例
pstmt.addBatch(); // 添加多条数据
pstmt.executeBatch();

// 获取所有生成的键
try (ResultSet keys = pstmt.getGeneratedKeys()) {
    while (keys.next()) {
        long id = keys.getLong(1);
        // 处理每个生成的键
    }
}

最佳实践

  1. 始终使用 try-with-resources:确保资源自动关闭。
  2. 验证返回结果:检查 ResultSet 是否有数据,避免空指针异常。
  3. 数据库兼容性测试:根据实际数据库调整 SQL 语法(如 Oracle 的序列)。

通过此示例,你可以轻松实现插入数据并获取自动生成的主键,适用于大多数关系型数据库!

相关文章:

  • angular中的路由传参
  • pbootcms版AI自动发文插件,自动发布自动配图,支持多任务
  • 数字化转型 2.0:AI、低代码与智能分析如何重塑企业竞争力?
  • 调试 ResNet18 cpp实现中的段错误(SIGSEGV)问题
  • Junit在测试过程中的使用方式,具体使用在项目测试中的重点说明
  • xLua_001 Lua 文件加载
  • R语言基于ggscitable包复现一篇3.5分的文章的连续变量交互效应(交互作用)的可视化图
  • 记一次线上SQL死锁事故
  • 【一】Vue组件开发教程
  • Halcon算子 二维码识别、案例
  • AI 时代的通信新范式:MCP(模块化通信协议)的优势与应用
  • openvela新时代的国产开源RTOS系统
  • [网络安全] 滥用Azure内置Contributor角色横向移动至Azure VM
  • QA:备份产品的存储架构采用集中式和分布式的优劣?
  • 如何配置本地git
  • QT软件匠心开发,塑造卓越设计服务
  • 智慧港口新未来:大数据赋能应急消防,筑牢安全防线
  • 关于numpy里面的轴(axis)
  • w264民族婚纱预定系统
  • Python 爬虫(4)HTTP协议
  • 中国结算澄清“严查场外配资”传闻:账户核查为多年惯例,无特殊安排
  • 外交部:各方应为俄乌双方恢复直接对话创造条件
  • 从《让·桑特伊》到《追忆》,假故事的胜利
  • 违法违规收集使用个人信息,爱奇艺、轻颜等65款App被点名
  • 中国-拉共体成员国重点领域合作共同行动计划(2025-2027)
  • 220名“特朗普币”持有者花1.48亿美元,获邀与特朗普共进晚餐