Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-02291: 违反完整约束条件 (SCOTT.SETMEAL_KEY) - 未找到父项关键字

今天做项目遇到这个问题:

在这里总结一下我的解决方法(Mybatis+Oracle):

业务逻辑是有个主表,中间表的外键是主表的主键,在插入数据到主表之后,需要返回主表的自增id到实体类(id),然后在将主表的id插入到中间表,但是运行时出现了上诉的错误。检查了数据库的表设计,原来表的通过触发器+序列来创建自增id的,因此如下插入会出现问题:

 <insert id="addToCheckGroup" parameterType="com.healthCloud.pojo.CheckGroup">
        <selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="id">
            select T_CHECKGROUP_SEQ.nextval from sys.dual
        </selectKey>
        INSERT INTO T_CHECKGROUP  Values(#{id},#{code},#{name},#{helpCode},#{sex},#{remark},#{attention})
    </insert>

 

出现这个问题的原因是程序在跑的时候,先触动了触发器,在调用上面的功能,id增加了2,并不是1.因此插入到中间表的时候id比插入到主表获取的id大1,两个id不一样,就找不到主表的id,报未找到父项关键字的错误,正确的解决方法:

方法1:更改数据库表的设计,去掉触发器,只用序列来获取只增id

-------------t_setmeal-------------------
CREATE TABLE t_setmeal (
  id NUMBER(11) NOT NULL,
  name VARCHAR2(500) DEFAULT NULL,
  code VARCHAR2(8) DEFAULT NULL,
  helpCode VARCHAR2(16) DEFAULT NULL,
  sex VARCHAR2(1) DEFAULT NULL,
  age VARCHAR2(32) DEFAULT NULL,
  price float DEFAULT NULL,
  remark VARCHAR2(500) DEFAULT NULL,
  attention VARCHAR2(500) DEFAULT NULL,
  img VARCHAR2(500) DEFAULT NULL,
  PRIMARY KEY (id)
) 


-- Create sequence 创建序列
create sequence T_SETMEAL_SEQ
minvalue 1    -- 最小值=1
maxvalue 999999999999999999999999999  -- 指定最大值 
-- 或nomaxvalue      -- 没有最大值
-- NOCYCLE;      -- 不循环
start with 12  -- 从12开始
increment by 1  -- 每次递增1
cache 20;

INSERT INTO t_setmeal VALUES (T_SETMEAL_SEQ.NEXTVAL, '入职无忧体检套餐(男女通用)', '0001', 'RZTJ', '0', '18-60', '300', '入职体检套餐', null, 'a5e8e729-74ce-4939-bf36-9cdc02fb2ae51.jpg');

Mybatis中插入数据并返回自增id(序列)

 <insert id="addToSetmeal" parameterType="com.healthCloud.pojo.Setmeal">
        <selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="id" >
            select T_SETMEAL_SEQ.nextval from sys.dual
        </selectKey>
        insert into T_SETMEAL (id,name, code, helpCode, sex, age, price, remark, attention, img) Values(#{id},#{name}, #{code}, #{helpCode}, #{sex}, #{age}, #{price}, #{remark}, #{attention}, #{img})
    </insert>

注意:没有触发器,需要先

SELECT T_SETMEAL_SEQ.nextval from dual;

但是id字段不能少,且手动添加数据时id不会自动增加

批量插入数据到中间表

 <insert id="addToSetmealAndCheckGroup" parameterType="java.util.List">
        INSERT INTO t_setmeal_checkgroup (setmeal_id,checkgroup_id)
        <foreach close=")" collection="Lists" item="item" index="index" open="(" separator="union all">
            SELECT
            #{item.setmealId,jdbcType=NUMERIC},
            #{item.checkgroupId,jdbcType=NUMERIC}
            FROM DUAL
        </foreach>
    </insert>

方法2:更改数据库表的设计,添加触发器,(触发器+序列)获取自增id

--创建触发器
create or replace trigger T_SETMEAL_TRI
  before insert on T_SETMEAL 
REFERENCING OLD AS "OLD" NEW AS "NEW" FOR EACH ROW
begin
    SELECT T_SETMEAL_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
end;

Mybatis中插入数据并返回自增id(触发器+序列)

<insert id="addToSetmeal" parameterType="com.healthCloud.pojo.Setmeal">
        <!--通过触发器+序列获取主键id-->
        <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id" >
            select T_SETMEAL_SEQ.CURRVAL  from sys.dual
        </selectKey>
        insert into T_SETMEAL (name, code, helpCode, sex, age, price, remark, attention, img) Values(#{name}, #{code}, #{helpCode}, #{sex}, #{age}, #{price}, #{remark}, #{attention}, #{img})
    </insert>

<!--批量插入到中间表-->
    <insert id="addToSetmealAndCheckGroup" parameterType="java.util.List">
        INSERT INTO t_setmeal_checkgroup (setmeal_id,checkgroup_id)
        <foreach close=")" collection="Lists" item="item" index="index" open="(" separator="union all">
            SELECT
            #{item.setmealId,jdbcType=NUMERIC},
            #{item.checkgroupId,jdbcType=NUMERIC}
            FROM DUAL
        </foreach>
    </insert>

 附带删除触发器,删除序列

DROP TRIGGER  T_SETMEAL_TRI --删除触发器

DROP SEQUENCE   T_SETMEAL_SEQ --删除序列

 

posted @ 2020-06-15 14:57  shadow321  阅读(2123)  评论(0编辑  收藏  举报