java - Hibernate orphanRemoval 移除所有行,然后插入行

标签 java hibernate jpa

以下示例已简化。

我有以下数据库结构:

X
 -xid VARCHAR

Y
 -yid VARCHAR
 -xid VARCHAR
 -zid VARCHAR
Z
 -zid VARCHAR

我有以下实体结构

@Entity
@Table(name = "X")
public class EntityX {
    @Id
    @Column(name = "xid")
    private String xid;

    @OneToMany(... mappedBy = "x", cascadeType.ALL, orphanRemoval=true)
    private List<EntityY> yList = new ArrayList();
    ...
}

@Entity
@Table(name = "Y")
public class EntityY {  
    @Id
    @Column(name = "yid")
    private String yid;

    @ManyToOne(cascadeType.ALL)
    private x;

    @ManyToOne(cascadeType.ALL)
    private z;
    ...
}

@Entity
@Table(name = "Z")
public class EntityZ {
    @Id
    @Column(name = "zid")
    private String zid;
}

我的保存方式是:

X x = new X();
x.setXid(1);

Z z = new Z();
z.setZid(1);

Z z2 = new Z();
z2.setZid(2);

Y y = new Y();
y.setYid(1);
y.setX(x);
y.setZ(z);

Y y2 = new Y();
y2.setYid(2);
y2.setX(x);
y2.setZ(z2);

List<Y> yList = new ArrayList<Y>();
yList.add(y);
yList.add(y2);
x.setYList(yList);

entityManager.persist(x);

保存工作正常,sqls 是:

insert into X (XID) values (1);
insert into Z (ZID) values (1);
insert into Y (YID, XID, ZID) values (1, 1, 1);
insert into Z (ZID) values (2);
insert into Y (YID, XID, ZID) values (2, 1, 2);

我的更新方法是:

X x = new X();
x.setXid(1);

Z z = new Z();
z.setZid(1);

Z z3 = new Z();
z3.setZid(3);

Y y = new Y();
y.setYid(1);
y.setX(x);
y.setZ(z);

Y y3 = new Y();
y3.setYid(3);
y3.setX(x);
y3.setZ(z3);

List<Y> yList = new ArrayList<Y>();
yList.add(y);
yList.add(y3);
x.setYList(yList);

entityManager.merge(x);

更新执行以下 sqls:

insert into Z (ZID) values (3);
insert into Y (YID, XID, ZID) values (3, 1, 3);

delete from Y where XID=1; Why?
delete from Z where XID=1; Why?
delete from Y where XID=2;
delete from Z where XID=2;

insert into Z (ZID) values (1); Why?
insert into Y (YID, XID, ZID) values (1, 1, 1); Why?

为什么Y(YID=1)和Z(ZID=1)在插入后被删除?如果有例如 100000 次 Y 和 Z 没有改变,这是一个性能问题。

最佳答案

尝试更新时,请勿尝试再次手动创建实体并执行合并。当您像上面那样在相关实体上设置级联选项时,您最终会遇到问题。

在合并期间,持久性上下文检索 x(xid=1) 实体以及 OneToMany 列表。您新创建的 X 实体虽然有一个新的列表实例。现在,持久性提供程序考虑了 orphanRemoval 标志,并决定之前的状态无效,并删除了 xid=1 的 Y 的所有内容(因为它们不存在于新列表中)。

然后它将新添加的元素插入到新列表中。

我建议首先使用 xid=1 获取 X,然后在持久性上下文管理的实体上执行更新:

X x = session.get(X.class, 1);
...

List<Y> yList = x.getYList();
yList.add(y);
yList.add(y3);

entityManager.merge(x);

全部在一个交易方法中。

关于java - Hibernate orphanRemoval 移除所有行,然后插入行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48168770/

相关文章:

java - LockModeType.PESSIMISTIC_WRITE 是否锁定结果行或整个表?

java - 将 java.io.File 子类化是一个坏主意吗?

java - 列出 Vertx 中所有已注册的路由

postgresql - JPA/hibernate/PostgresDB 和 Vaadin 8 : SQL select query to get data from inherited tables and show in Vaadin grid

java - 制作一个 Spring Boot 应用程序来从现有的 Oracle 数据库加载数据?

hibernate - 一对多多关系

java - 暂停时如何恢复 MediaPlayer

java - 为什么我在 getString() 上得到一个空指针异常?

java - 显示键/值数据的更好方法是什么

java - Spring 和 Hibernate3 的 @Embeddable 问题