Mysql 如何使用JPA和Hibernate对新实体的子实体执行级联合并

Mysql 如何使用JPA和Hibernate对新实体的子实体执行级联合并,mysql,hibernate,jpa,spring-boot,spring-data-jpa,Mysql,Hibernate,Jpa,Spring Boot,Spring Data Jpa,这个问题涉及到管理身份证号码,以确保我不会在我的个人表格上出现重复的身份。这是一个带有MySQL数据库的springboot项目 一些背景: 我有一个提交“插曲”的HTML表单。每一集都包含“人”,并且与许多人的“人”有关系 “剧集”由现场工作人员输入并提交到数据库(db1)。几小时后,后台工作人员将该插曲手动输入第二个数据库(db2) 在我的spring附加数据库(db1)中,我有一个persons表,它有一个本机自动生成的id字段。db1还有一个id2字段,它记录来自db2的人员的唯一id

这个问题涉及到管理身份证号码,以确保我不会在我的个人表格上出现重复的身份。这是一个带有MySQL数据库的springboot项目

一些背景:

我有一个提交“插曲”的HTML表单。每一集都包含“人”,并且与许多人的“人”有关系

“剧集”由现场工作人员输入并提交到数据库(db1)。几小时后,后台工作人员将该插曲手动输入第二个数据库(db2)

在我的spring附加数据库(db1)中,我有一个persons表,它有一个本机自动生成的id字段。db1还有一个id2字段,它记录来自db2的人员的唯一id

现场工作人员在进入一集时并不总是可以访问id2,但后台工作人员可以

当我保存一个新的“插曲”时,我需要save方法来检查数据库中是否存在personid2,并对person执行更新(而不是创建新的)

然后删除重复的人

事件实体:

@Entity
public class Episode {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
@Column(name="start_date")
@DateTimeFormat (pattern="dd/MM/yyyy HH:mm")
private Date start_date;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "episode_person", joinColumns = @JoinColumn(name = "episode_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id"))
private List<Person> persons;
@OneToOne(cascade=CascadeType.ALL)
//@JoinColumn(name = "id")
private Address address;
PersonServiceImpl

@Override
@Transactional
public Episode saveEpisode(Episode episode) {
    List mergedPeople = personService.mergeDetachedWithAttached( episode.getPersons() );
    episode.setPersons( mergedPeople );
    return episodeRepository.save(episode);
}
    @Transactional
@Override
public List mergeDetachedWithAttached(List<Person> people) {
    final List<Person> results = new ArrayList<>();
    if ( people != null && !people.isEmpty() ) {

        // loop over every person
        for (Person person : people) {

            // for current person try to retrieve from db via Id2
            Person db2Person = personRepository.findById2( person.getId2() );

            // if a person was retrieved use them instead of submitted person
            if (db2Person != null ) {
                System.out.println("A matching person was found in the db using id2 - this is the person that will be added");
                results.add(db2Person);
            } else {
                results.add(person);
            }
        }
    }
    return results;
@Transactional
@凌驾
公共列表合并DetachedWithAttached(列出人员){
最终列表结果=新建ArrayList();
if(people!=null&&!people.isEmpty()){
//环顾每个人
用于(人:人){
//对于当前人员,请尝试通过Id2从数据库中检索
Person db2Person=personRepository.findById2(Person.getId2());
//如果检索到一个人,请使用他们而不是提交的人
if(db2Person!=null){
System.out.println(“使用id2在数据库中找到了一个匹配的人-这就是要添加的人”);
结果:添加(db2Person);
}否则{
结果:增加(人);
}
}
}
返回结果;
在提交新剧集时,我会创建新的人物,即使我使用id2从db1中成功地查找了他们并将他们添加到剧集中

我如何处理此问题,以便:


我可以在比较id2的基础上合并重复的身份。如果合并后删除了一个id,则保存了插曲id和人物id的连接表也需要更新。

如果将
@manytomy
关联替换为2个双向
@OneToMany
关联,这意味着您可以映射关联,这会容易得多还有一张桌子

这样,考虑到您有那些重复的
实体,您可以通过简单地调整关联实体上的
@ManyToOne
关联来轻松移动加入的关联。对于重复的
,您可以使用上文所述的UPSERTow,或者在通过批处理将条目添加到数据库中后手动合并

通常,当多个节点同时运行时,可以使用数据库UPSERT或MERGE操作

您可以将UPSERT与Hibernate相结合


要处理FK更新,您需要使用FK ON DELETE级联策略。

@vladmihalcea问题分为两部分(1)关于级联更新和(2)合并。合并问题的实质是:id2跟踪唯一的人。因为id2在第一次提交剧集的过程开始时并不总是可用。因此,当最终输入id2时,可能会发现db1中已经存在该人(通过查找id2)。此时,我需要使用任何新的详细信息更新现有的db1 person,并删除重复的person。(包括更新联接表).Check-then-act逻辑总是容易受到并发问题的影响。如果在检查之后,某个并发线程已经插入了有问题的实体,该怎么办?正确执行该操作的唯一方法是使用UPSERT。
    @Transactional
@Override
public List mergeDetachedWithAttached(List<Person> people) {
    final List<Person> results = new ArrayList<>();
    if ( people != null && !people.isEmpty() ) {

        // loop over every person
        for (Person person : people) {

            // for current person try to retrieve from db via Id2
            Person db2Person = personRepository.findById2( person.getId2() );

            // if a person was retrieved use them instead of submitted person
            if (db2Person != null ) {
                System.out.println("A matching person was found in the db using id2 - this is the person that will be added");
                results.add(db2Person);
            } else {
                results.add(person);
            }
        }
    }
    return results;