Java 使用objectify的多对多关系?
我正在将我的应用程序从关系数据库移动到objectify/google应用程序引擎 应用程序具有如下建模的关系: 一条Java 使用objectify的多对多关系?,java,google-app-engine,objectify,Java,Google App Engine,Objectify,我正在将我的应用程序从关系数据库移动到objectify/google应用程序引擎 应用程序具有如下建模的关系: 一条消息可以发送给许多用户。每个用户都可以收到许多消息s 我需要能够扫描发送给特定用户的所有消息 如何使用Objectify实现这一点?有多种方法 您可以在用户对象中保存消息列表。这将很好地满足您将所有消息发送给用户的需求,因为不需要进行查询 您可以在消息对象中保存用户列表。要获取所有发送给单个用户的消息,请执行查询 您可以保存上面的两个列表。请记住,在应用程序引擎中,通常不需要规范
消息
可以发送给许多用户
。每个用户
都可以收到许多消息
s
我需要能够扫描发送给特定用户的所有消息
如何使用Objectify实现这一点?有多种方法
您可以在用户对象中保存消息列表。这将很好地满足您将所有消息发送给用户的需求,因为不需要进行查询
您可以在消息对象中保存用户列表。要获取所有发送给单个用户的消息,请执行查询
您可以保存上面的两个列表。请记住,在应用程序引擎中,通常不需要规范化,也不需要担心磁盘空间和副本。几乎总是构建您的结构,以便查询速度更快
您可以忘记列表,使用关系对象就像关系数据库中的表一样。在某些用例中,它仍然是appengine中的不错的选项,例如,当列表太大(数千个)时,会使对象膨胀,甚至可能无法查询
最重要的变量将决定在您指定的查询中采用哪种方法,即通常向单个用户发送多少条消息,以及消息的最大数量?如果我们说的是平均几十条或更少,最多几百条,那么用户对象中的消息列表在我看来是一个不错的选择。如果我们谈论的是更多,尤其是无限的话,那么它就不能很好地工作,您需要进行实际的查询。您必须自己维护这种关系。这是因为根据应用程序的不同,让用户在没有消息的情况下存在是有意义的,甚至相反
Objectify Wiki(多值关系)建议的方法是保留键的集合(或数组)
公共类消息
{
@Id字符串时间戳;
键[]目的地;
}
公共类用户
{
@Id字符串名称;
关键字[]收件箱;
}
然后,如果要在删除用户时删除所有用户消息,只需在删除用户之前将其从数据存储中删除即可。如果您想为特定用户添加新消息,也同样如此。除了已经发布的答案之外,我建议您不要包含从用户到消息的链接,原因有三:
- GAE中的藏品严格限制为5000件。一旦用户的收件箱超过5k个项目,你的应用程序就会开始抛出异常
- 扩展实体中的数据量会带来性能成本;加载一组500k实体比加载一组5k实体慢。另外,memcache的使用效率会降低,因为您可以在同一空间中容纳更少的项目。用户对象往往会被大量加载
- 您可以轻松达到单个实体的交易速率限制(1/s)。如果50个人同时向您发送一条消息,您将遇到大量并发问题,因为所有50个人都会以乐观的失败重试
如果一封邮件的收件人限制为5000人,那么在邮件中存储目标密钥集(并为该集编制索引,以便查询用户的所有邮件)可能是一个很好的解决方案。几乎可以肯定的是,将消息分配给发送者的@Parent也有好处
如果你是推特,并希望消息有超过5K的接收者,或者如果你的消息通常有很多接收者(因此消息实体被臃肿),你可能会考虑Brett Slatkin在谷歌I/O会话中从2009:“/P>+ 1”中谈到的关系索引实体模式。这里的关键是改变对
消息的感知:在RDBMS中,您将消息视为一条绝对的“信息”,通过查询与用户连接。在数据存储中,用户拥有一份邮件副本,就像电子邮件一样:在你的Gmail帐户中,你不在乎发件人是否在发送邮件后删除邮件,一旦你收到邮件,你实际上“拥有”了一份与发件人断开连接的副本。要“发送”一封邮件
,您必须将一份副本放入发件人的“已发送”框和收件人的“收件箱”框中。谢谢您的提示。我预计每封邮件的收件人不到5000人。但是我怎样才能让邮件成为发件人的父级呢?你的意思不是相反吗?因为一旦有人创建了一条消息,它将始终来自他们,而不能来自其他任何人。似乎,如果项目超过5000,创建另一个实体来存储关系是最好的解决方案(类似于关系数据库映射表)
public class Message
{
@Id String timeStamp;
Key<User>[] destination;
}
public class User
{
@Id String name;
Key<Message>[] inbox;
}