Google App Engine乐观并发

Sno*_*man 2 database google-app-engine

我正在阅读Google App Engine 的文档,并偶然发现了一些我不太了解的内容:

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

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

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

Ada*_*son 5

虽然我不能代表像MongoDB之类的文档数据库(也就是NoSQL),但我可以告诉你,关系数据库只允许一个操作生效.但是,这归结为操作的内容.

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

用户1:

update MyTable set Col1 = '1', Col2 = '2' where ID = 'abc'
Run Code Online (Sandbox Code Playgroud)

用户2:

update MyTable set Col2 = 'x', Col3 = 'y' where ID = 'abc'
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

ID = 'abc'
Col1 = '1_original'
Col2 = '2_original'
Col3 = '3_original'
Run Code Online (Sandbox Code Playgroud)

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

用户1:

update MyTable set Col1 = '1', Col2 = '2', Col3 = '3_original' where ID = 'abc'
Run Code Online (Sandbox Code Playgroud)

用户2:

update MyTable set Col1 = '1_original', Col2 = 'x', Col3 = 'y' where ID = 'abc'
Run Code Online (Sandbox Code Playgroud)

现在我们遇到了问题; 即使我们的第二个命令确实不关心值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'
Run Code Online (Sandbox Code Playgroud)

用户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'
Run Code Online (Sandbox Code Playgroud)

这意味着最后命中数据库的命令实际上不会执行任何操作,因为列将不再具有其原始值.


Gui*_*sum 5

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

你误读了关于插入的一点; 通常插入使用不同的键,因此根本不会有争用.(只有在应用程序明确设置相同的密钥时,它们才会使用相同的密钥.)