首页 > 技术文章 > onetomany单向一对多java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails ()

jnhs 2020-08-31 17:20 原文

2020-9-1更新:

一方的外键字段写错了。

导致外键和多方的主键重名

下边是正确的一方的外键

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "poolid")//stockpool中该字段为外键,股票表中指向本表的外键名称
    public Set<Stock> getStocks() {
        return stocks;
    }

    public void setStocks(Set<Stock> stocks) {
        this.stocks = stocks;
    }

对比一下原来一方中错误的外键

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "id")//stockpool中该字段为外键,股票表中指向本表的外键名称
    public Set<Stock> getStocks() {
        return stocks;
    }

    public void setStocks(Set<Stock> stocks) {
        this.stocks = stocks;
    }

找到原因了吧?就偷了个懒,把所有的id都简单写为id,所以就出问题了,多方中本来就有id,而且还是主键,一方中又想指派一个外键叫做id,那就挂掉了。所以有时候少打几个字母,效率不仅不会高,而且还会翻车

修复之后,问题解决,成功向数据库插入数据

 

 

非常奇怪的一个问题: 单向一对多,一方管理。只能插入一条数据,第二条数据就无法插入

如下为一方

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.hs.model;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;

/**
 *
 * @author wishr
 */
@Entity
@Table(name = "t_stockpoolding")
public class StockPool implements Serializable {

    private int id;
    private String name;
    private String description;
    private Timestamp createDt;
    private Set<Stock> stocks = new HashSet<>();

    @Id
    @GeneratedValue(generator = "_native")
    @GenericGenerator(name = "_native", strategy = "native")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Timestamp getCreateDt() {
        return createDt;
    }

    public void setCreateDt(Timestamp createDt) {
        this.createDt = createDt;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "id")//stockpool中该字段为外键,股票表中指向本表的外键名称
    public Set<Stock> getStocks() {
        return stocks;
    }

    public void setStocks(Set<Stock> stocks) {
        this.stocks = stocks;
    }

}

 

 如下为多方,很简单,一个股票池中有很多股票,我找到一个股票池,就可以找到一堆股票,我可以向股票池添加股票,也可以从股票池删除股票,也可以删除股票池以全部删除股票,但是至于哪个股票在哪个股票池,我不关心

典型的一对多,单向

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.hs.model;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;

/**
 *
 * @author wishr
 */
@Entity
@Table(name = "t_stockding")
public class Stock implements Serializable {

    private int id;
    private String stockCode;
    private String stockName;

    @Id
    @GeneratedValue(generator = "_native")
    @GenericGenerator(name = "_native", strategy = "native")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getStockCode() {
        return stockCode;
    }

    public void setStockCode(String stockCode) {
        this.stockCode = stockCode;
    }

    public String getStockName() {
        return stockName;
    }

    public void setStockName(String stockName) {
        this.stockName = stockName;
    }

}

 

 再来看服务层代码,省略掉一些无关紧要的代码

  StockPool sp = spd.getByName(session, poolname);//从数据库中查到要操作的股票池

 

 

  Set<Stock> stocksInPool = sp.getStocks();//从股票池中拿出股票列表

 

 stocksInPool.add(stockWhichOnDealing);//给当前股票池加入这个股票   

 

sp.setStocks(stocksInPool);//更新该股票池的股票集合
spd.update(session, sp);//持久化

 

然后再省略一些无关紧要的事务操作。

如果第一次添加,是没问题的

数据表删干净

 

首先创建一个股票池

 

表也自动创建完成

 

向股票池中添加一个股票,成功

 

 debug数据正常

 

 持久化后也正常

 

 然后我重新添加一个

这就不行了,报错了

java.sql.SQLIntegrityConstraintViolationException: 
Cannot add or update a child row: a foreign key constraint fails 
(`networth_ding`.`t_stockding`, CONSTRAINT `FK_pi66wsimny0t01abiw8wm5ql9` FOREIGN KEY (`id`) REFERENCES `t_stockpool` (`id`))

 

 

 百撕不得骑姐!!!

为什么,第二次再保存,为什么就不行了呢?而且也定位不到问题,好愁人

 

 

 

z

推荐阅读