ORA-02291完整性约束违反求助:插入JV_SNAPSHOT时父键未找到
JPA一对一映射插入数据触发外键约束错误问题
我尝试向JV_SNAPSHOT、JV_GLOBAL_ID、JV_COMMIT三个表插入数据,对应的实体类如下:
@Entity @Table(name = "JV_SNAPSHOT") public class JVSnapshot { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jv_snapshot_pk_seq") @SequenceGenerator(name="jv_snapshot_pk_seq", sequenceName = "JV_SNAPSHOT_PK_SEQ") @Column(name = "SNAPSHOT_PK") private long snapshotID; @Column(name="VERSION") private long version; @Column(name="GLOBAL_ID_FK") private long globalID; @Column(name="COMMIT_FK") private long commitID; @Column(name = "TYPE") private String type; @Column(name = "MANAGED_TYPE") private String managedType; @Column(name = "STATE") private String state; @Column(name = "CHANGED_PROPERTIES") private String changedProperties; @OneToOne(mappedBy = "jvSnapshot") //@JoinColumn(name = "id") private JVGlobalID jvGlobalID; @OneToOne(mappedBy = "jvSnapshot") //@JoinColumn(name = "id") private JVCommit jvCommit; }
@Entity @Table(name = "JV_GLOBAL_ID") public class JVGlobalID { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jv_global_id_pk_seq") @SequenceGenerator(name="jv_global_id_pk_seq", sequenceName = "JV_GLOBAL_ID_PK_SEQ") @Column(name = "GLOBAL_ID_PK") private long globalID; @Column(name = "LOCAL_ID") private String localID; @Column(name = "FRAGMENT") private String fragment; @Column(name = "TYPE_NAME") private String typeName; @Column(name="OWNER_ID_FK") private long ownerID; @OneToOne @MapsId private JVSnapshot jvSnapshot; }
@Entity @Table(name = "JV_COMMIT") public class JVCommit { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jv_commit_pk_seq") @SequenceGenerator(name="jv_commit_pk_seq", sequenceName = "JV_COMMIT_PK_SEQ") @Column(name= "COMMIT_PK" , insertable = true, updatable = false) private long id; @Column(name = "AUTHOR") private String author; @Column(name = "COMMIT_DATE") private Date commitDate; @Column(name = "COMMIT_DATE_INSTANT") @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ") private String commitDateInstant; @Column(name="COMMIT_ID") private long commitId; @OneToOne @MapsId private JVSnapshot jvSnapshot; }
包含计算值及插入数据完整业务逻辑的Service类如下:
JVSnapshot jvSnapshot = new JVSnapshot(); //inserting data into JV_GLOBAL_ID table System.out.println("Inserting in JV_GLOBAL_ID table"); JVGlobalID jvGlobalId = new JVGlobalID(); jvGlobalId.setTypeName("com.dev.neo.models.Customer"); jvGlobalId.setLocalID("99999"); jvCommitGlobalIdRepository.save(jvGlobalId); //globalID generated (PK) System.out.println("Data inserted in jvcommitGlobalrespository"); //inserting data into JV_COMMIT table System.out.println("Inserting in JV_COMMIT table"); JVCommit jvCommit = new JVCommit(); List<Long> jvCommitObjectList = jvCommitRepository.getMaxCommitId(); Long commitId = jvCommitObjectList.get(0) + 1; String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); String date = simpleDateFormat.format(new Date()); jvCommit.setAuthor(req.getCheckerId()); jvCommit.setCommitDate(new Date()); jvCommit.setCommitDateInstant(date); jvCommit.setCommitId(commitId); System.out.println("Data inserted Successfully"); jvSnapshot.setJvCommit(jvCommit); jvCommitRepository.save(jvCommit); //id generated (PK) System.out.println("JV_COMMIT Data saved Successfully"); jvSnapshot.setCommitID(jvCommit.getId()); jvSnapshotRepository.save(jvSnapshot); //inserting data into JV_SNAPSHOT table System.out.println("Inserting in JV_SNAPSHOT table"); //CLOB Datatypes variables String existingCustomerIDNew = "somenewString"; String existingCustomerID = "someString"; jvSnapshot.setState(existingCustomerIDNew); jvSnapshot.setChangedProperties(existingCustomerID); jvSnapshot.setManagedType("com.dev.neo.models.Customer"); jvSnapshot.setType("UPDATE"); jvSnapshot.setVersion(2); jvSnapshot.setGlobalID(jvGlobalId.getGlobalID()); System.out.println("Data inserted in all JV");
执行所有步骤后,数据未写入表中,且出现错误:Caused by: java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (SYSTEM.JV_SNAPSHOT_GLOBAL_ID_FK) violated - parent key not found
JV_SNAPSHOT_GLOBAL_ID_FK是JV_SNAPSHOT表中GLOBAL_ID_FK列的外键约束名,该列关联JV_GLOBAL_ID表的主键列GLOBAL_ID_PK。我已尝试多种方式声明这些表的一对一映射,但均未解决问题。
问题根源
- 映射配置混乱:
@MapsId配置要求JVGlobalID、JVCommit的主键与JVSnapshot主键一致,但你又给这两个实体配置了独立序列生成主键,同时JVSnapshot手动维护外键字段,导致映射逻辑冲突。 - 插入顺序与关联维护错误:先保存关联实体但未建立双向关联,后续给
JVSnapshot设置外键后未重新保存,且插入JV_SNAPSHOT字段的时机晚于首次保存操作。
修复方案
1. 修正实体类映射
以JVSnapshot作为关联主控方,由JPA自动维护外键,删除手动维护的外键字段:
JVSnapshot.java
@Entity @Table(name = "JV_SNAPSHOT") public class JVSnapshot { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jv_snapshot_pk_seq") @SequenceGenerator(name="jv_snapshot_pk_seq", sequenceName = "JV_SNAPSHOT_PK_SEQ") @Column(name = "SNAPSHOT_PK") private long snapshotID; @Column(name="VERSION") private long version; @Column(name = "TYPE") private String type; @Column(name = "MANAGED_TYPE") private String managedType; @Column(name = "STATE") private String state; @Column(name = "CHANGED_PROPERTIES") private String changedProperties; // 主控方,维护GLOBAL_ID_FK外键 @OneToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "GLOBAL_ID_FK", referencedColumnName = "GLOBAL_ID_PK") private JVGlobalID jvGlobalID; // 主控方,维护COMMIT_FK外键 @OneToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "COMMIT_FK", referencedColumnName = "COMMIT_PK") private JVCommit jvCommit; // 省略getter/setter }
JVGlobalID.java
@Entity @Table(name = "JV_GLOBAL_ID") public class JVGlobalID { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jv_global_id_pk_seq") @SequenceGenerator(name="jv_global_id_pk_seq", sequenceName = "JV_GLOBAL_ID_PK_SEQ") @Column(name = "GLOBAL_ID_PK") private long globalID; @Column(name = "LOCAL_ID") private String localID; @Column(name = "FRAGMENT") private String fragment; @Column(name = "TYPE_NAME") private String typeName; @Column(name="OWNER_ID_FK") private long ownerID; // 被动方,关联主控方属性 @OneToOne(mappedBy = "jvGlobalID") private JVSnapshot jvSnapshot; // 省略getter/setter }
JVCommit.java
@Entity @Table(name = "JV_COMMIT") public class JVCommit { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jv_commit_pk_seq") @SequenceGenerator(name="jv_commit_pk_seq", sequenceName = "JV_COMMIT_PK_SEQ") @Column(name= "COMMIT_PK" , insertable = true, updatable = false) private long id; @Column(name = "AUTHOR") private String author; @Column(name = "COMMIT_DATE") private Date commitDate; @Column(name = "COMMIT_DATE_INSTANT") @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ") private String commitDateInstant; @Column(name="COMMIT_ID") private long commitId; // 被动方,关联主控方属性 @OneToOne(mappedBy = "jvCommit") private JVSnapshot jvSnapshot; // 省略getter/setter }
2. 修正Service插入逻辑
利用级联保存特性,仅保存主实体即可自动同步关联数据,同时建立双向关联:
// 初始化主实体并设置自身字段 JVSnapshot jvSnapshot = new JVSnapshot(); String existingCustomerIDNew = "somenewString"; String existingCustomerID = "someString"; jvSnapshot.setState(existingCustomerIDNew); jvSnapshot.setChangedProperties(existingCustomerID); jvSnapshot.setManagedType("com.dev.neo.models.Customer"); jvSnapshot.setType("UPDATE"); jvSnapshot.setVersion(2); // 初始化JV_GLOBAL_ID并建立双向关联 JVGlobalID jvGlobalId = new JVGlobalID(); jvGlobalId.setTypeName("com.dev.neo.models.Customer"); jvGlobalId.setLocalID("99999"); jvSnapshot.setJvGlobalID(jvGlobalId); jvGlobalId.setJvSnapshot(jvSnapshot); // 初始化JV_COMMIT并建立双向关联 JVCommit jvCommit = new JVCommit(); List<Long> jvCommitObjectList = jvCommitRepository.getMaxCommitId(); Long commitId = jvCommitObjectList.get(0) + 1; String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); String date = simpleDateFormat.format(new Date()); jvCommit.setAuthor(req.getCheckerId()); jvCommit.setCommitDate(new Date()); jvCommit.setCommitDateInstant(date); jvCommit.setCommitId(commitId); jvSnapshot.setJvCommit(jvCommit); jvCommit.setJvSnapshot(jvSnapshot); // 级联保存主实体及关联实体 jvSnapshotRepository.save(jvSnapshot); System.out.println("所有表数据插入完成");
关键说明
- 删除
JVSnapshot中手动维护的globalID、commitID字段,由@JoinColumn自动维护外键,避免手动赋值错误。 - 使用
CascadeType.PERSIST级联保存,确保主实体保存时关联实体同步入库,保证外键关联有效性。 - 必须同时设置双向关联的双方属性,否则JPA无法正确识别关联关系。
内容的提问来源于stack exchange,提问作者Rahulv
相关产品推荐
相关产品推荐

