2

我正在阅读 Google App Engine 的文档,偶然发现了一些我不太理解的东西:

Datastore 使用乐观并发来管理事务。当两个或多个应用程序实例尝试同时更改同一个实体组时(通过更新现有实体或创建新实体),第一个提交更改的应用程序将成功,所有其他应用程序将在提交时失败。然后这些其他应用程序可以再次尝试它们的事务以将它们应用于更新的数据。请注意,由于 Datastore 以这种方式工作,因此使用实体组会限制您可以对给定组中的任何实体执行的并发写入次数。

这是否意味着如果来自两个不同设备的两个不同用户尝试修改同一个对象,则只有其中一个会成功?这是典型的数据库行为,还是只是 GAE 限制?其他数据库通常如何处理这种情况,即两个或多个用户试图修改同一个对象?

当两个或更多应用程序实例尝试创建新实体时,只有一个会成功,这意味着什么。我理解错了吗?没有两个应用程序实例可以将新对象添加到同一张表中吗?

4

2 回答 2

5

虽然我不能说像 MongoDB 之类的文档数据库(又名 NoSQL),但我可以告诉你,关系数据库只允许一个操作生效。但是,这归结为操作什么。

例如,假设两个用户试图修改同一个对象。如果他们的修改只修改了列的一个子集,比如说......

用户 1:

update MyTable set Col1 = '1', Col2 = '2' where ID = 'abc'

用户 2:

update MyTable set Col2 = 'x', Col3 = 'y' where ID = 'abc'

您可以确定Col1它将是 '1' 并且Col3' will be 'y', as those two columns were only updated in one statement. The value ofCol2` 将由最后执行的命令确定。

同样,如果一个用户更新了该行而另一个用户删除了它,那么无论如何都会删除该行。如果更新用户的命令首先出现,则更新将成功,然后将删除该行。如果删除命令先出现,那么该行将首先被删除并且更新不会做任何事情,因为该行不存在(该where子句将不匹配任何行)。

但是,实际上很少有应用程序会费心使用仅包含已更改列的命令来更新数据库。在几乎所有应用程序中,命令都是在表级别创建的,它们会更新所有列,然后将“当前”(更改或未更改)值传递给这些命令。这就是使用乐观并发的原因。

假设该行abc当前具有以下值:

ID = 'abc'
Col1 = '1_original'
Col2 = '2_original'
Col3 = '3_original'

并且两个用户同时检索了该行,我们上面的命令将更真实地看起来像这样:

用户 1:

update MyTable set Col1 = '1', Col2 = '2', Col3 = '3_original' where ID = 'abc'

用户 2:

update MyTable set Col1 = '1_original', Col2 = 'x', Col3 = 'y' where ID = 'abc'

现在我们有一个问题;即使我们的第二个命令真的不关心 中的值Col1,它也可能会覆盖用户 1 设置的值。同样,如果用户 2 先命中,那么用户 1 将覆盖用户 2 写入的值Col3

乐观并发本质上扩展了where子句来检查每一列的值,而不仅仅是表的键。通过这种方式,您可以确保在检索行和保存行之间的时间段内不会覆盖其他人(或某物)所做的任何更改。

因此,给定相同的条件,我们的命令将如下所示:

用户 1:

update MyTable set Col1 = '1', Col2 = '2', Col3 = '3_original' where ID = 'abc' 
        and Col1 = '1_original' and Col2 = '2_original' and Col3 = '3_original'

用户 2:

update MyTable set Col1 = '1_original', Col2 = 'x', Col3 = 'y' where ID = 'abc'
        and Col1 = '1_original' and Col2 = '2_original' and Col3 = '3_original'

这意味着无论哪个命令最后访问数据库实际上都不会做任何事情,因为列将不再具有它们的原始值。

于 2012-04-14T03:34:08.387 回答
5

事务的 API 重试几次(默认 3 次,总共 4 次尝试)。假设您的事务函数执行诸如读取实体、更新属性、将其写回、重试也会重新读取等操作。因此,除非存在严重争用,否则通常您不会注意到失败。

您误读了有关插入的内容;通常插入使用不同的键,因此根本不会发生争用。(只有在应用程序明确设置相同的密钥时,它们才会使用相同的密钥。)

于 2012-04-14T04:40:27.643 回答