以下示例已简化。
我有以下数据库结构:
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没有改变,则这是性能问题。
答案 0 :(得分:2)
当您尝试更新时,请勿尝试再次手动创建实体并执行合并。当你在上面的相关实体上设置了级联选项时,你最终会遇到问题。
在合并期间,持久性上下文检索x(xid = 1)实体以及OneToMany列表。您新创建的X实体虽然有一个新的列表实例。现在,持久性提供程序需要考虑orphanRemoval
标志并确定前一个状态无效,任何删除Y的所有内容xid = 1(因为它们不在新列表中)。
然后它在新列表中插入新添加的元素。
我建议首先使用xid = 1获取X,然后在持久性上下文管理实体上执行更新:
X x = session.get(X.class, 1);
...
List<Y> yList = x.getYList();
yList.add(y);
yList.add(y3);
entityManager.merge(x);
所有这些都在一个交易方法中。