通过合并了解关系级联

Understanding Relationship Cascading with Merge

深入研究 Spring JPA,我很难理解这里发生了什么。 这是代码:

实体

@Entity
public class PersonP {

    @Id @GeneratedValue
    private int id;

    public String name;

    @ManyToMany
    public List<PersonP> knows = new LinkedList<>();

    @ManyToMany(mappedBy = "knows", cascade = CascadeType.ALL)
    public List<PersonP> knownBy = new LinkedList<>();

    public PersonP(){}

    public PersonP(String name) {
        this.name = name;
    }
}

SpringBootApp

@SpringBootApplication
@EntityScan(basePackageClasses = Demo.class)
public class Demo implements CommandLineRunner {

    @PersistenceContext
    EntityManager em;

    public static void main(String[] args) {
        new SpringApplicationBuilder(Demo.class).run(args);
    }

    @Override
    @Transactional
    public void run(String... args) throws Exception {
        sample();
    }

    @Transactional
    public void sample(){
        PersonP p1 = new PersonP("P1");
        PersonP p2 = new PersonP("P2");
        PersonP p3 = new PersonP("P3");
        PersonP p4 = new PersonP("P4");
        PersonP p5 = new PersonP("P5");

        p1.knows.add(p2);
        p2.knows.add(p3);
        p5.knows.add(p3);

        p1.knownBy.add(p3);
        p3.knownBy.add(p2);
        p2.knownBy.add(p4);

        p1 = em.merge(p1);

        p1.name = "x1";
        p2.name = "x2";
        p3.name = "x3";
        p4.name = "x4";
        p5.name = "x5";
    }

通过启动应用程序,数据库中会生成以下内容:

我已经到了生成所有人员的地步,但我希望 PERSONP_KNOWS table 中有一个额外的条目,例如p2.knownBy.add(p4); 但事实并非如此。我假设自从调用 merge 之后,关联的实体也会被保存(p1 知道 p2,p4 知道 p2)。不过好像不是这样的…… 为什么会这样?

如您所见,并不是所有的人都被持久化(P5 在数据库中缺失),而且您可能想要的所有关系也不是。

缺少 P5 的原因是您仅沿着 knownBy 相关人员级联合并操作:
P1 -> P3 -> P2 -> P4
P5 不是 knownBy 任何人,因此级联合并未达到)


当四个实体中的每一个都被持久化时,关于它拥有拥有方的关联的信息也会被持久化。
在你的例子中,拥有方knows(因为knownBymappedBy="knows")。
所以唯一保留的 association-information 是:
P1 (ID1) -> P2 (ID3)
P2 (ID3) -> P3 (ID2)

(请注意,P2 具有 ID 3,这令人困惑,但由于 ID 已生成且后来被保留,因此有意义)

P5 -> P3 不会持久化,因为 P5 根本不会持久化(如上所述)


因此,要正确保存所有信息,请始终确保 bi-directional 关联同步。并注意在 @ManyToMany 关联上进行级联操作时的潜在问题,因为这可能导致性能问题(大量级联操作)和意外结果(例如,当级联删除时)。

https://vladmihalcea.com/jpa-hibernate-synchronize-bidirectional-entity-associations/
https://thorben-janssen.com/avoid-cascadetype-delete-many-assocations/