在GAE中实施唯一约束

abe*_*bel 6 google-app-engine unique datastore

我正在尝试使用Google App Engine Java,但是缺少一个独特的约束条件会让事情变得困难.我已经阅读过这篇文章,这个博客提出了一种实现类似方法的方法.我的背景是在MySQL.Moving到数据存储没有一个独特的约束让我感到紧张,因为我从来不必担心重复值之前和检查每个值之前插入一个新值仍然有错误的余地.

"不,你仍然无法在架构创建过程中指定唯一的."

- David Underhill谈论GAE和唯一约束(后链接)

你们用什么来实现类似于唯一或主键的东西?

我听说过使用低级api创建的抽象数据存储层,它像普通的RDB一样工作,然而它不是免费的(但是我不记得软件的名称)

我的问题的示意图

sNo = biggest serial_number in the db
sNo++
Insert new entry with sNo as serial_number value //checkpoint
User adds data pertaining to current serial_number 
Update entry with data where serial_number is sNo 
Run Code Online (Sandbox Code Playgroud)

但是在第3行(检查点),我觉得两个用户可能会添加相同的sNo.这就是阻止我使用appengine的原因.

Jas*_*all 12

在讨论从传统RDB过渡到像App Engine这样的类似BigTable的数据存储时,这个问题和其他类似问题经常出现.

讨论数据存储区不支持唯一键的原因通常很有用,因为它会在考虑数据存储方案时通知您应该处于的思维模式.独特约束不可用的原因是它极大地限制了可伸缩性.就像你说的那样,强制执行约束意味着检查该属性的所有其他实体.无论您是在代码中手动执行还是数据存储在幕后自动执行,它仍然需要发生,这意味着性能降低.可以进行一些优化,但仍需要以某种方式进行.

你的问题的答案是,真的想想为什么你需要这个独特的约束.

其次,请记住密钥确实存在于数据存储区中,并且是实施简单唯一约束的好方法.

my_user = MyUser(key_name=users.get_current_user().email())
my_user.put()
Run Code Online (Sandbox Code Playgroud)

这将保证MyUser永远不会再使用该电子邮件创建,您还可以MyUser使用该电子邮件快速检索:

my_user = MyUser.get(users.get_current_user().email())
Run Code Online (Sandbox Code Playgroud)

在python运行时中,您还可以执行以下操作:

my_user = MyUser.get_or_create(key_name=users.get_current_user().email())
Run Code Online (Sandbox Code Playgroud)

这将使用该电子邮件插入或检索用户.

任何比这更复杂的东西都不会扩展.因此,请真正考虑您是否需要该属性是全局唯一的,或者是否有方法可以消除对该唯一约束的需求.通常情况下,您会发现一些小的变通方法,您根本不需要该属性.

  • 但是两个执行线程不能用相同的密钥执行put(),最后一个获胜吗?上面的例子并没有真正提出问题的RDBMS精神中的"唯一约束".相反,您必须首先使用事务并检查实体的存在(使用祖先查询),然后创建实体.否则,您将覆盖现有实体. (6认同)

Ada*_*and 4

您可以为产品生成唯一的序列号,而无需强制执行唯一 ID 或查询整个实体集以找出当前最大的序列号。您可以使用事务和单例实体来生成“下一个”序列号。由于操作发生在事务内,因此您可以确保没有两个产品会获得相同的序列号。

然而,这种方法将成为潜在的性能瓶颈并限制应用程序的可扩展性。如果新序列号的创建并不经常发生而导致争用,那么它可能适合您。

编辑:为了澄清,保存当前或下一个要分配的序列号的单例完全独立于实际分配有序列号的任何实体。它们不需要都是实体组的一部分。您可以使用相同的机制让来自多个模型的实体获得新的、唯一的序列号。

我对 Java 的记忆不太好,无法提供示例代码,而且我的 Python 示例对您来说可能毫无意义,但这里有伪代码来说明这个想法:

  1. 接收创建新库存项目的请求。
  2. 输入交易。
  3. 检索 SerialNumber 模型的单个实体的当前值。
  4. 增加值并将其写入数据库
  5. 退出交易时返回值。

现在,完成实际创建库存项目并将其与其新序列号一起存储的所有工作的代码不需要在事务中运行。

注意:正如我上面所说,这可能是一个主要的性能瓶颈,因为一次只能创建一个序列号。但是,它确实可以确保您刚刚生成的序列号是唯一的且未被使用。