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

Oracle数据库下SimpleJdbcInsert保存数据遇ORA-01400错误求助

解决Oracle下JdbcTemplate保存时ID不能为NULL的问题

问题原因

H2数据库支持自增主键(AUTO_INCREMENT),SimpleJdbcInsert的usingGeneratedKeyColumns("id")可以自动识别并生成主键;但Oracle数据库默认没有自增列(12c之前),通常依赖序列+触发器实现主键自动生成,或者12c+使用IDENTITY列。当前代码中SimpleJdbcInsert在Oracle下无法自动生成ID,且插入时传递了id=null,违反主键非空约束。

解决方案

方案1:利用序列+触发器(传统Oracle方式)

假设你的ITEM表对应序列为SEQ_ITEM_ID,先创建自动赋值的触发器:

CREATE OR REPLACE TRIGGER TRG_ITEM_ID
BEFORE INSERT ON SUWAN.ITEM
FOR EACH ROW
WHEN (NEW.ID IS NULL)
BEGIN
    SELECT SUWAN.SEQ_ITEM_ID.NEXTVAL INTO :NEW.ID FROM DUAL;
END;
/

修改JdbcTemplateItemRepositoryV3的构造器,让SimpleJdbcInsert忽略id字段(由触发器自动赋值):

public JdbcTemplateItemRepositoryV3(DataSource datasource) {
    this.template = new NamedParameterJdbcTemplate(datasource);
    this.jdbcInsert = new SimpleJdbcInsert(datasource)
            .withTableName("item")
            .withSchemaName("SUWAN") // 指定你的schema
            .usingColumns("item_name", "price", "quantity") // 仅插入业务字段,排除id
            .usingGeneratedKeyColumns("id"); // 声明id是生成的主键,用于返回
}

save方法无需修改,executeAndReturnKey会自动获取触发器生成的ID并设置到Item对象中。

方案2:手动获取序列值(无触发器场景)

如果没有创建触发器,可在保存前手动从序列获取ID并设置到Item对象:

@Override
public Item save(Item item) {
    // 从序列获取下一个ID值
    String seqSql = "select SUWAN.SEQ_ITEM_ID.nextval from dual";
    Long newId = template.queryForObject(seqSql, Collections.emptyMap(), Long.class);
    item.setId(newId);
    
    // 插入数据
    SqlParameterSource param = new BeanPropertySqlParameterSource(item);
    jdbcInsert.execute(param);
    return item;
}

同时修改构造器,无需usingGeneratedKeyColumns(因为ID已手动设置):

public JdbcTemplateItemRepositoryV3(DataSource datasource) {
    this.template = new NamedParameterJdbcTemplate(datasource);
    this.jdbcInsert = new SimpleJdbcInsert(datasource)
            .withTableName("item")
            .withSchemaName("SUWAN");
}

方案3:Oracle 12c+ IDENTITY列(自增列)

如果使用Oracle 12c及以上版本,且ITEM表的id列定义为IDENTITY自增列:

CREATE TABLE SUWAN.ITEM (
    ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    ITEM_NAME VARCHAR2(100),
    PRICE NUMBER,
    QUANTITY NUMBER
);

此时只需确保JDBC驱动版本支持IDENTITY列(推荐Oracle JDBC驱动12.2+),原代码的SimpleJdbcInsert配置即可正常工作,若仍报错,可尝试添加withSchemaName指定schema:

public JdbcTemplateItemRepositoryV3(DataSource datasource) {
    this.template = new NamedParameterJdbcTemplate(datasource);
    this.jdbcInsert = new SimpleJdbcInsert(datasource)
            .withTableName("item")
            .withSchemaName("SUWAN")
            .usingGeneratedKeyColumns("id");
}

验证步骤

  1. 确认ITEM表的主键约束和ID生成方式(序列/触发器/IDENTITY)
  2. 对应修改代码中的SimpleJdbcInsert配置或save方法
  3. 重新测试保存操作,检查ID是否正确生成且无ORA-01400错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 10:27:09