面试题答案
一键面试CouchDB内置冲突处理策略
- 版本向量:CouchDB使用版本向量来跟踪文档的不同版本。每个文档都有一个
_rev
(修订版本号),每次文档更新时,_rev
会改变。当冲突发生时,CouchDB会保存所有冲突版本的文档。这些冲突版本会以数组形式存储在_conflicts
字段中,每个元素包含冲突版本的_rev
。例如,一个文档有两个冲突版本1-abc
和2-def
,_conflicts
字段可能像["1-abc", "2-def"]
。 - 最后写入者胜出(LWW):默认情况下,CouchDB采用最后写入者胜出策略。在同步过程中,当检测到冲突时,较新的修订版本会被视为有效版本并保存,较旧的版本会被标记为冲突。“新”的判断依据是基于修订版本号的生成顺序,生成顺序靠后的为新。
自定义冲突处理逻辑以满足特定业务需求
- 使用JavaScript函数:CouchDB允许在设计文档中定义JavaScript函数来处理冲突。可以通过在设计文档的
_conflicts
字段下定义函数。例如:
{
"_id": "_design/conflict_handler",
"_conflicts": {
"resolve": "function (doc, conflicts) {
// 自定义逻辑开始
for (var i = 0; i < conflicts.length; i++) {
var conflict = conflicts[i];
// 可以根据文档内容、修订版本号等判断
if (conflict.indexOf('specific_rev_pattern')!== -1) {
return conflict;
}
}
// 如果没有符合条件的,返回第一个冲突版本
return conflicts[0];
}"
}
}
这个函数接收文档对象doc
和冲突版本数组conflicts
。可以在函数内部根据业务逻辑,如文档的特定字段值、修订版本号模式等,选择要保留的版本。
2. 基于文档内容的判断:如果业务需求依赖于文档的具体内容,比如文档中有一个表示重要性的字段importance
。在冲突处理函数中,可以遍历冲突版本,比较importance
字段的值,选择importance
值最大的版本。示例代码如下:
{
"_id": "_design/conflict_handler",
"_conflicts": {
"resolve": "function (doc, conflicts) {
var bestConflict = null;
var highestImportance = -1;
for (var i = 0; i < conflicts.length; i++) {
var conflict = conflicts[i];
var conflictDoc = getDoc(conflict);
if (conflictDoc.importance > highestImportance) {
highestImportance = conflictDoc.importance;
bestConflict = conflict;
}
}
return bestConflict;
}"
}
}
这里假设getDoc
函数可以根据_rev
获取对应的文档。通过这种方式,可以根据业务数据的实际含义来解决冲突,满足特定业务需求。