【问题标题】:Understanding Relationship Cascading with Merge了解关系级联与合并
【发布时间】:2022-02-02 03:09:48
【问题描述】:

深入了解 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 表中有一个额外的条目,例如对于p2.knownBy.add(p4); 但它不是。我假设自从调用merge 之后,关联的实体也会被保存(p1 知道 p2,p2 也被 p4 知道)。不过好像不是这样的…… 为什么会这样?

【问题讨论】:

    标签: java spring-data-jpa relationship jpa-2.0 cascading


    【解决方案1】:

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

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


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

    (请注意,P2 具有 ID 3,这很令人困惑,但由于 ID 已生成并随后被持久化,因此有意义)

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


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

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

    【讨论】:

    • (另请注意,更新p2-5 的名称不会持久化,因为只有p1 持有对合并到持久化上下文中的实体的引用。)stackoverflow.com/a/1070629
    • 太好了,非常感谢您的回答!我仍然不清楚,为什么 P4 也被保存了?由于 P4 也不为任何人所知。其余的对我来说绝对有意义:)
    • p2.knownBy.add(p4);--> merge 级联从 p2p4
    • 那么,这样总结是否正确? - 将存储来自所有者方的所有关联关系 - 将存储所有引用的实体
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多