虽然我不能说像 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 of
Col2` 将由最后执行的命令确定。
同样,如果一个用户更新了该行而另一个用户删除了它,那么无论如何都会删除该行。如果更新用户的命令首先出现,则更新将成功,然后将删除该行。如果删除命令先出现,那么该行将首先被删除并且更新不会做任何事情,因为该行不存在(该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'
这意味着无论哪个命令最后访问数据库实际上都不会做任何事情,因为列将不再具有它们的原始值。