冲突
在分布式数据库中,数据副本可能存储在一个以上的位置。 网络的自然网络和系统特性可能意味着,对存储在某一位置的文档所做的更改无法即时更新或复制到数据库的其他部分。 存储在某个位置的文件所做的更改无法即时更新或复制到数据库的其他部分。
换句话说 可以对不同的文件副本进行独立更新。 这些更新可能会导致对文件的正确、明确内容产生分歧或“冲突”。
IBM® Cloudant® for IBM Cloud® 尝试通过向您提醒潜在问题来帮助避免冲突。 它会通过对有问题的更新请求返回 409
响应来向您发出警告。 但是 如果是在一个当前未连接网络的系统上请求数据库更新,则可能收不到 409
响应。 系统当前未连接到网络。
例如 例如,数据库可能位于暂时断开互联网连接的移动设备上。 这样就无法检查是否进行了其他潜在冲突的更新。 更新。
如果您申请的文件存在冲突情况、 IBM Cloudant会如期返回文档。 不过,内部算法在决定返回哪个文档版本之前会考虑很多因素。 您不能假定返回的文件是最新版本。
例如,如果您不检查冲突、 或不处理冲突、 您的IBM Cloudant数据库可能会出现以下行为:
- 由于出现更多相互冲突的文件,文件内容的不一致性不断增加。
- 增加数据库容量,因为必须保留所有冲突文件,直到冲突得到解决。
- 由于IBM Cloudant在响应每个请求时都必须更加努力地识别冲突文档的“最佳”版本,因此会降低性能。
以下建议的实践可能有助于您决定何时检查和解决冲突:
应用程序特征 | 更新文档的频率 | 检索时是否检查冲突? | 更新时是否检查冲突? |
---|---|---|---|
始终连接网络,例如服务器。 | 经常 | Y |
|
始终连接到网络。 | 有时 |
|
Y |
经常但不总是与网络连接,例如笔记本电脑。 | 经常 |
|
Y |
经常但不始终连接到网络。 | 有时 |
|
Y |
偶尔连接网络,例如平板电脑。 | 经常 |
|
Y |
查找冲突
要查找可能影响文档的任何冲突、 在检索文档时添加查询参数 conflicts=true
。 返回时、 生成的文件包括一个 _conflicts
数组、 数组,其中包括所有冲突修订的列表。
请参阅下面的地图功能示例,以查找文件冲突:
function (doc) {
if (doc._conflicts) {
emit(null, [doc._rev].concat(doc._conflicts));
}
}
要在数据库中查找多个文档的冲突,请编写视图。 使用 map 函数(例如,提供的示例),可以查找存在冲突的每个文档的所有修订版。
如果您有此类视图,可以将其用于根据需要查找和解决冲突。 或者,可以在每次复制后查询视图来立即识别和解决冲突。
如何解决冲突
发现冲突后,可以通过以下四个步骤来解决。
- 获取
- 合并
- 上传
- 删除(T)
请参见以下第一个版本的示例文档:
{
"_id": "74b2be56045bed0c8c9d24b939000dbe",
"_rev": "1-7438df87b632b312c53a08361a7c3299",
"name": "Samsung Galaxy S4",
"description": "",
"price": 650
}
让我们为这个例子设想一个场景。 假设您拥有一家在线商店的产品数据库。 文档的第一个版本可能类似于提供的示例。
请参阅以下第二版(第一修订版)文件,其中增加了说明:
{
"_id": "74b2be56045bed0c8c9d24b939000dbe",
"_rev": "2-61ae00e029d4f5edd2981841243ded13",
"name": "Samsung Galaxy S4",
"description": "Latest smartphone from Samsung",
"price": 650
}
由于文档尚未包含描述,因此可能有人会添加描述。
请参阅以下第二版备选文件,该版本对第一版文件进行了降价数据更改:
{
"_id": "74b2be56045bed0c8c9d24b939000dbe",
"_rev": "2-f796915a291b37254f6df8f6f3389121",
"name": "Samsung Galaxy S4",
"description": "",
"price": 600
}
与此同时,其他人利用复制的数据库降低了价格。 这是对文档第一个版本进行的更改。 因此、 降价变化并不“知道”描述的变化。
之后,复制两个数据库时,可能不清楚文档的两个备用版本中哪个是对的。 这个例子是一个冲突场景。
获取冲突修订版
要查找文档的任何冲突修订版,请正常检索该文档,但包含 conflicts=true
参数,与以下示例类似:
https://ACCOUNT.cloudant.com/products/$_ID?conflicts=true
请参阅下面的文档检索响应示例,其中显示了相互冲突的修订:
{
"_id":"74b2be56045bed0c8c9d24b939000dbe",
"_rev":"2-f796915a291b37254f6df8f6f3389121",
"name":"Samsung Galaxy S4",
"description":"",
"price":600,
"_conflicts":["2-61ae00e029d4f5edd2981841243ded13"]
}
如果文档存在任何冲突,根据更改的描述或更改的价格问题,您会收到与提供的示例类似的响应。
任意选择价格发生变化的版本作为文件的最新版本。 不要认为最近更新的文件版本就是解决冲突的最新版本。
In this example, consider a conflict between the retrieved document, which has the _rev
value 2-f796915a291b37254f6df8f6f3389121
, and another document, which has the _rev
value 2-61ae00e029d4f5edd2981841243ded13
.
在 _conflicts
数组中记录了冲突文档详细信息。
通常情况下 你可能会发现数组中只有一个元素、 但也有可能出现许多相互冲突的修订。 每个修订版都列在数组中。
合并更改
您的应用程序必须识别和协调所有可能的更改,从而有效合并正确、有效的更新,以生成文档的单个非冲突版本。
要比较修订版本并确定哪些内容发生了更改、 应用程序必须从数据库中检索所有版本。 首先,您需要检索文件和任何冲突版本的详细信息。 要开始检索,请使用类似下面的命令、 该命令也请求 _conflicts
数组:
https://$ACCOUNT.cloudant.com/products/$_ID?conflicts=true
这种检索可为您提供所存储文件的当前版本、
以及必须检索的所有其他冲突文件的列表、 例如 ...rev=2-61ae00e029d4f5edd2981841243ded13
和 ...rev=1-7438df87b632b312c53a08361a7c3299
。 还会检索并存储所有这些冲突版本,例如:
https://$ACCOUNT.cloudant.com/products/$_ID?rev=2-61ae00e029d4f5edd2981841243ded13
https://$ACCOUNT.cloudant.com/products/$_ID?rev=1-7438df87b632b312c53a08361a7c3299
一旦有了文档的所有冲突修订版,就可以解决冲突、 就可以解决冲突。
在先前的方案中、 文档版本之间的差异是文档中不同字段的差异、 这样就更容易进行合并。
更复杂的冲突可能需要相应进行更多分析。 帮助、 你可以选择各种解决冲突的策略、 例如
有关如何实现这些更改的实用示例,请参阅此项目及样本代码。
上传新修订版
在解决并合并之前冲突修订中的改动后,请查看以下最终修订:
{
"_id": "74b2be56045bed0c8c9d24b939000dbe",
"_rev": "3-daaecd7213301a1ad5493186d6916755",
"name": "Samsung Galaxy S4",
"description": "Latest smartphone from Samsung",
"price": 600
}
评估并解决冲突后、 创建一份包含当前数据和最终数据的文件。 这一全新文档将上传到数据库。
删除旧修订版
请参阅以下请求示例,删除旧版本:
DELETE https://$ACCOUNT.cloudant.com/products/$_ID?rev=2-61ae00e029d4f5edd2981841243ded13
DELETE https://$ACCOUNT.cloudant.com/products/$_ID?rev=2-f796915a291b37254f6df8f6f3389121
最后一步,删除旧版本。 您可以通过发送 DELETE
请求来删除旧版本、 指定要删除的修订版本。
删除文档的旧版本时、 与该文件相关的冲突就会被标记为已解决。 您可以通过再次申请文件来验证是否存在冲突。 将 conflicts
参数设置为 true,并像以前一样使用
查找冲突。