You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java PreparedStatement.getGeneratedKeys()在DB2不生效但MySQL正常问题

问题背景

我在MySQL与DB2中均创建了名为STUDENT的简单表,字段如下:ID(主键、自增)、FIRST_NAME、LAST_NAME、AGE。两库的表结构做了对齐,语法层面无差异。
编写Java程序执行插入操作时,MySQL环境可通过PreparedStatement.getGeneratedKeys()正常返回生成的主键,DB2环境却无任何返回结果。
DB2与MySQL执行连接提交后,均能成功插入数据,多次插入时ID可正常自增,但仅MySQL环境可进入while(rs.next())遍历到生成的键值,DB2的结果集为空,会直接跳过遍历逻辑。

问题复现代码
String sql = "INSERT INTO STUDENT (FIRST_NAME, LAST_NAME, AGE) VALUES ('Jacob', 'Eldy', 19)"

final Connection connection = getConnection(dataSource.get());

int[] insertedRows = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
    ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
    ps.addBatch();
    
    insertedRows = ps.executeBatch();

    rs = ps.getGeneratedKeys();
    
    while(rs.next()) {
        LOGGER.info(rs.getString(1));
    }
    connection.commit();
} catch (Exception e) {
    try {
        connection.rollback();
    } catch (SQLException e) {
        e.printStackTrace();
    }

} finally {
    close(ps, connection);
}
附:建表DDL

MySQL DDL

CREATE TABLE 'STUDENT'
  ...
  `ID` int NOT NULL AUTO_INCREMENT
  PRIMARY KEY('ID')
  AUTO_INCREMENT=19073

DB2 DDL

CREATE TABLE STUDENT
(
  ID INTEGER DEFAULT IDENTITY GENERATED ALWAYS NOT NULL
  PRIMARY KEY (ID)
)
问题原因与解决方案

这个问题不是基础代码写法错误,核心是DB2 JDBC驱动的兼容性限制,加上自增列的非标准写法导致驱动无法识别生成键:

  • 版本低于10.5的DB2 JDBC驱动(老版本db2jcc.jar)本身不支持executeBatch()批量执行场景下返回自增主键,只有单条调用executeUpdate()时,Statement.RETURN_GENERATED_KEYS参数才会生效。
  • 你写的DB2自增列语法是非标准写法,标准IDENTITY列定义顺序为GENERATED ALWAYS AS IDENTITY,你写的DEFAULT IDENTITY GENERATED ALWAYS属于数据库容错兼容的写法,部分驱动版本无法识别该列为自动生成的标识列,自然不会返回对应键值。

最优处理方案按优先级排序:

  1. 先修正DB2表的自增列定义为标准语法,调整后DDL参考:
CREATE TABLE STUDENT
(
  ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL,
  FIRST_NAME VARCHAR(50),
  LAST_NAME VARCHAR(50),
  AGE INTEGER,
  PRIMARY KEY (ID)
)
  1. 升级DB2 JDBC驱动到10.5及以上版本(使用db2jcc4.jar),该版本开始正式支持批量插入场景下的生成键返回,升级后原有代码无需修改即可正常拿到自增ID。
  2. 如果受生产环境限制无法升级驱动,分两种场景处理:
    • 单条插入场景:直接调用ps.executeUpdate()替代addBatch() + executeBatch()的批量写法,即可正常通过getGeneratedKeys()获取自增主键
    • 必须使用批量插入的场景:每批次执行完成后,在同一个连接内执行SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1,即可拿到当前会话最后一次生成的自增主键,按插入顺序即可和批次内的数据做ID映射。

注意:IDENTITY_VAL_LOCAL()是会话级函数,不会被其他数据库连接的插入操作影响,只要保证插入和查询在同一个Connection内、中间没有执行其他同表的插入操作,拿到的ID值就是准确的。

内容的提问来源于stack exchange,提问作者stackerstack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:45:30