H2 参照完整性约束违反

Posted

技术标签:

【中文标题】H2 参照完整性约束违反【英文标题】:H2 Referential integrity constraint violation 【发布时间】:2019-01-21 12:06:43 【问题描述】:

我正在使用 Spring Boot 应用程序的 H2 数据库。我创建了一个帐户服务类,用于保存帐户、帐户类型和客户的数据。请在下面找到代码:

默认构造函数、Getter Setter、使用所有字段的构造函数、toString、hashCode、equals 都存在于以下每个类中。

作为实体的帐户 POJO 以及数据传输对象,即 DTO

@Entity
@Table(name = "ACCOUNT")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Account 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @OneToOne
    @JoinColumn(name="account_type_id")
    private AccountType accountType;

    @Temporal(TemporalType.DATE)
    @Column(name = "date_created", unique = true, nullable = false, length = 10)
    private Date dateCreated;

    @Column(nullable = false)
    private double originalCreditAmount;

    @Column(nullable = false)
    private double balanceAmount;

    @Column(nullable = false)
    private boolean fullyPaid;

    @Column(nullable = false)
    private int term;

    @Column(nullable = false)
    private float rateOfInterest;

    @Column(nullable = false)
    private boolean escrowAttached;

    @Column(nullable = false)
    private boolean pmiAttached;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_id", nullable = false)
    @JsonBackReference
    Customer customer;

AcountType POJO 作为实体以及数据传输对象,即 DTO

@Entity
@Table(name = "ACCOUNT_TYPE")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class AccountType 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String accountTypeName;

    @Column(nullable = false)
    private String accountTypeDescription;


作为实体的客户 POJO 以及数据传输对象,即 DTO

@Entity
@Table(name = "customer")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String firstName;

    @Column(nullable = false)
    private String lastName;

    @Column(nullable = false)
    private String socialSecurityNumber;

    @Temporal(TemporalType.DATE)
    @Column(name = "dob", unique = true, nullable = false, length = 10)
    private Date dateOfBirth;

    @Column(nullable = false)
    private double totalLoanAmount;

    @Column(nullable = false)
    private int bonusPoints;

    @Temporal(TemporalType.DATE)
    @Column(name = "customer_since", unique = true, nullable = false, length = 10)
    private Date memberSince;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Address> addresses = new HashSet<Address>();

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Account> accounts = new HashSet<Account>();

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Contact> contacts = new HashSet<Contact>();


    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Education> education = new HashSet<Education>();

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Employment> employment = new HashSet<Employment>();

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Investment> investments = new HashSet<Investment>();


    @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
    @JsonManagedReference
    private Set<Liability> liabilities = new HashSet<Liability>();


    @Column()
    private int rating;

当我尝试通过 POST 调用创建客户、帐户和帐户类型时:


"customer": 
"id": 1,
"firstName": "Jordaya",
"lastName": "Scott",
"dateOfBirth": "1980-04-12",
"totalLoanAmount": 287000,
"bonusPoints": 70000,
"memberSince": "2000-04-11",
"socialSecurityNumber": "449-84-4944",
"rating": 7
,
"accountType": 
"id": 2,
"accountTypeName": "Savings A/C",
"accountTypeDescription": "Savings Account"
,
"dateCreated": "2017-01-01",
"originalCreditAmount": 300000,
"balanceAmount": 200000,
"fullyPaid": false,
"term": 30,
"rateOfInterest": 3.25,
"escrowAttached": false,
"pmiAttached": false

失败并出现以下错误。

org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FKGW84MGPACW9HTDXCS2J1P7U6J: PUBLIC.ACCOUNT FOREIGN KEY(ACCOUNT_TYPE_ID) REFERENCES PUBLIC.ACCOUNT_TYPE(ID) (2)"; SQL statement:
insert into account (account_type_id, balance_amount, customer_id, date_created, escrow_attached, fully_paid, original_credit_amount, pmi_attached, rate_of_interest, term, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

请纠正我对错误的理解。我认为这个错误即将到来,因为客户和帐户类型记录不是在数据库中创建的,因此当帐户被插入数据库时​​,它无法找到帐户类型 ID,因此会引发此错误。

【问题讨论】:

【参考方案1】:

是的,如果不存在具有匹配 ID 的实体,您将违反完整性约束。

如果您想实现相关实体的级联创建,您应该将cascade 添加到您的关系映射中。例如:

@OneToOne(cascade = CascadeType.ALL...)

但即便如此,当您发送具有特定 ID 的 JSON 数据并且它们在 DB 中不存在时,您也会收到此错误。

【讨论】:

我将 cascade = CascadeType.ALL 添加到 Account 类中的 Join Columns(Account Type 和 Customer)中,并再次尝试 POST 请求,但失败并出现错误“将分离的实体传递给持久化:com.microservice。 model.AccountType;" 如果没有执行持久化的代码,很难说出了什么问题,但看起来您正在尝试保存 ID 已设置为特定值的级联帐户类型。您需要将其保留为空。但问题是这是否是你想要的。如果 DB 中存在具有此 ID 的帐户类型,则需要先检索它。

以上是关于H2 参照完整性约束违反的主要内容,如果未能解决你的问题,请参考以下文章

org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException:违反参照完整性约束

Hibernate/H2 @OneToMany 删除子时“违反参照完整性约束”?

JPA 中的参照完整性约束违反错误

ORA-02291: 违反完整约束条件 (*) - 未找到父项关键字

ORA-02292: 违反完整约束条件 处理

MS ACCESS 完整性约束违反:NOT NULL 检查约束;