我的项目中有三个实体类
public class Blobx {
@ManyToOne
private Userx user;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
}
public class Index {
@Id
private String keyword;
@OneToMany(cascade = CascadeType.PERSIST)
private List<Blobx> blobs;
}
public class Userx {
@Id
private String name;
@OneToMany(mappedBy = "user")
private List<Blobx>blobs;
}
在运行以下行时,app引擎会抛出异常
em.getTransaction().begin();
em.persist(index);
em.getTransaction().commit();//exception is thrown
em.close();
作为
Caused by: java.lang.IllegalArgumentException: can't operate on multiple entity groups in a single transaction. found both Element
{
type: "Index"
name: "function"
}
and Element {
type: "Userx"
name: "18580476422013912411"
}
我无法理解什么是错的?
答案 0 :(得分:1)
正在发生的事情(基于错误消息)是您尝试保留Index
,其中包含Blobx
个es,其中包含Userx
个es,这些都是不同的实体组,在交易中。当你调用em.persist(index)
时,它会级联持有其中的所有实体以及它们内的所有实体。
将实体组视为一组机器。您的一些Index
es位于内华达州的群集A中。其中包含的Blobx
es位于缅因州的群集B中,其中包含的Userx
es位于德克萨斯州和俄勒冈州的群集B和C中。它们如何最终完全是随机的,并且(完全没有你的代码)完全不受你的控制。要求App Engine坚持所有这些地理位置不同的实体并知道何时失败(即在交易中)几乎是不可能的,并且需要大量的网络串扰才能让所有各方都知道所有其他方都做得很好。所以这是不允许的。
您要做的是确保Google将您的所有实体放在一个实体组中,这意味着它们都在一个(地理位置)。要做到这一点,请阅读the docs for Transactions,其中描述了如何确保您的实体最终在同一个实体组中,这意味着他们将能够对所有实体进行交易。
现在,实体分组的事情有它的缺点。即数据存储的缓慢和不均匀利用(例如,现在所有实体都将在德克萨斯州,俄勒冈州的用户将看到不必要的缓慢!),因此如果您绝对需要在所有实体上使用事务,则仅使用实体组。例如,除非实际必须,否则不要使用级联持久性,除非实际需要,否则不要在事务中执行。