【问题标题】:Google App Engine optimistic concurrencyGoogle App Engine 乐观并发
【发布时间】:2012-04-14 03:24:19
【问题描述】:

我正在阅读 Google App Engine 的 documentation 并偶然发现了一些我不太明白的东西:

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

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

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

【问题讨论】:

  • 注意代码的设计:将多个条目放在同一个实体组中可以使查询更快,但对并发问题有一些限制

标签: database google-app-engine


【解决方案1】:

虽然我不能代表 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 将覆盖写入Col3 的值由用户 2.

乐观并发本质上扩展了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'

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-28
      • 1970-01-01
      相关资源
      最近更新 更多