我正在学习AppEngine并开始开发新的应用程序,并希望澄清一些内容。
我明白了 一个。为了实现更新/删除多个实体的原子性,我们需要在事务中执行它,因此所有实体都应该属于同一个实体组 湾拥有大型实体组是不可扩展的,因为它会导致争用。 (Q1:正确?)
所以这是一个在线考试系统的实体模型,以供讨论:
实体: 学科 考试 页 题 答案
从顶部可以看出,每个实体1 - 与直接底层的许多关系,即1个主题可以有很多考试,1个考试 - >很多页面,1页可以有很多问题......
正如你所看到的,我想在这些实体之间建立级联更新/删除关系(JPA datanucleus appengine实现通过将所有实体放在同一个实体组(Q2:Correct?)下来支持这个(引擎盖下)虽然AppEngine本身不支持这种约束)所以自然所有人都会在同一个实体组下面这样做 一个。我可以在交易中删除一个页面(如果我的用户这样做)并确保所有页面,问题和答案都被删除 湾或者我可以在交易中完全删除一个主题,清除所有内容
因此,当我将其扩展到我的真实应用程序时,我发现我的所有(或至少大多数)实体都是相互关联的,并且适合于相同的实体组,以便能够完全交换它们 - 使我的模型效率低下。
问题3:请就如何重新思考此设计(以及最佳实践)提出建议,并仍然实现我的需求。如果需要,请向我询问。 如果你能指出我相关的例子,那就太好了。
P.S。我能想到的解决方案是将每个实体放在一个单独的实体组中,并将每个实体中的一个单独的持久字段(比如Exam)命名为'IS_DELETED',默认为FALSE(值为0)。一旦用户删除了考试,我将该字段设置为1(TRUE)并且我不再加载它们。我将编写一个Cron作业,在后端单独的单独事务中清除所有相关实体,如果需要,将在失败时重试。但我相信这不是很优雅,也不确定这是否会成功..
感谢大家的回复, 哈里
答案 0 :(得分:2)
改善事物的最简单方法之一就是首先拥有更少的实体。我真的不能想到一个非常好的理由,为什么页面,问题和答案需要是独立的实体。我怀疑你通常会在同一个请求中显示所有问题,无一例外。如果确实如此,那就把它们放在一个实体中。
将Exam实体用作页面的父级确实很有意义;一方面,每次考试可能仅限于合理的少量页面,因此扩大规模可能不会太大。
另一方面,每个科目可能 进行了大量的考试,因此,科目应该不出现在考试的血统中(并且通过扩展) ,页面)。
如果由于某种原因你需要删除数学主题中的所有考试,即使它们在同一个实体组中,你可能无法在没有超时的情况下在一个事务中完成整个删除。您甚至可能无法在单个请求中完成删除操作。
这表明您应该使用任务队列进行此操作。当主题发生级联更改时,请求处理程序需要插入新任务然后才能成功返回。不要忘记在请求处理程序中直接更新主题实体。
任务队列从数据存储中提取受影响的实体块,更新它们,然后检查时间。如果还有更多时间可用于持续更新,则会拉出另一个实体块,依此类推,直到没有剩余。如果时间差不多了,那么任务只会将自己添加回队列中,以便在重新生成时重新启动。
最好在初始请求的未来至少几秒内安排第一个任务,这样,例如,如果主题被删除,删除可以传播到将来的请求,并且没有新的考试可以在任务开始时创建主题。