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"); }
验证步骤
- 确认
ITEM表的主键约束和ID生成方式(序列/触发器/IDENTITY) - 对应修改代码中的
SimpleJdbcInsert配置或save方法 - 重新测试保存操作,检查ID是否正确生成且无ORA-01400错误
内容的提问来源于stack exchange,提问作者everycoffee
相关产品推荐
相关产品推荐

