Mysql 如何使用JPA和Hibernate对新实体的子实体执行级联合并
这个问题涉及到管理身份证号码,以确保我不会在我的个人表格上出现重复的身份。这是一个带有MySQL数据库的springboot项目 一些背景: 我有一个提交“插曲”的HTML表单。每一集都包含“人”,并且与许多人的“人”有关系 “剧集”由现场工作人员输入并提交到数据库(db1)。几小时后,后台工作人员将该插曲手动输入第二个数据库(db2) 在我的spring附加数据库(db1)中,我有一个persons表,它有一个本机自动生成的id字段。db1还有一个id2字段,它记录来自db2的人员的唯一id 现场工作人员在进入一集时并不总是可以访问id2,但后台工作人员可以 当我保存一个新的“插曲”时,我需要save方法来检查数据库中是否存在personid2,并对person执行更新(而不是创建新的) 然后删除重复的人 事件实体: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
@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;