Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database googleappengine乐观并发_Database_Google App Engine - Fatal编程技术网

Database googleappengine乐观并发

Database googleappengine乐观并发,database,google-app-engine,Database,Google App Engine,我正在阅读谷歌应用程序引擎的应用程序,偶然发现了一些我不太理解的东西: 数据存储使用乐观并发来管理事务。什么时候 两个或多个应用程序实例尝试更改同一实体组 同时(通过更新现有实体或创建 第一个提交更改的应用程序将成功 所有其他人都会在承诺时失败。然后,可以使用这些其他应用程序 请重试其事务以将其应用于更新的数据。注 这是因为数据存储以这种方式工作,使用实体组限制 可以对给定数据库中的任何实体执行的并发写入数 小组 这是否意味着,如果来自两个不同设备的两个不同用户尝试修改同一对象,那么其中只有一个

我正在阅读谷歌应用程序引擎的应用程序,偶然发现了一些我不太理解的东西:

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

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


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

虽然我不能为MongoDB等文档数据库(也称为NoSQL)说话,但我可以告诉您,关系数据库只允许一个操作生效。然而,这取决于操作是什么

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

用户1:

update MyTable set Col1 = '1', Col2 = '2' where ID = 'abc'
update MyTable set Col1 = '1', Col2 = '2', Col3 = '3_original' where ID = 'abc'
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 Col2 = 'x', Col3 = 'y' where ID = 'abc'
update MyTable set Col1 = '1_original', Col2 = 'x', Col3 = 'y' where ID = 'abc'
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'
您可以确定
Col1
将是“1”,而
Col3”将是“y”,因为这两列仅在一条语句中更新。
Col2`的值将由最后执行的命令决定

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

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

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

ID = 'abc'
Col1 = '1_original'
Col2 = '2_original'
Col3 = '3_original'
如果两个用户同时检索该行,我们上面的命令将更真实地显示如下:

用户1:

update MyTable set Col1 = '1', Col2 = '2' where ID = 'abc'
update MyTable set Col1 = '1', Col2 = '2', Col3 = '3_original' where ID = 'abc'
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 Col2 = 'x', Col3 = 'y' where ID = 'abc'
update MyTable set Col1 = '1_original', Col2 = 'x', Col3 = 'y' where ID = 'abc'
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'
现在我们有一个问题;尽管我们的第二个命令实际上并不关心
Col1
中的值,但它可能会覆盖用户1设置的值。同样,如果用户2首先点击,那么用户1将覆盖用户2写入
Col3
的值

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

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

用户1:

update MyTable set Col1 = '1', Col2 = '2' where ID = 'abc'
update MyTable set Col1 = '1', Col2 = '2', Col3 = '3_original' where ID = 'abc'
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 Col2 = 'x', Col3 = 'y' where ID = 'abc'
update MyTable set Col1 = '1_original', Col2 = 'x', Col3 = 'y' where ID = 'abc'
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'

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

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


你误读了关于插入的部分;通常插入使用不同的密钥,所以根本不会有争用。(只有在应用程序显式设置相同的密钥时,它们才会使用相同的密钥。)

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