介绍
开发人员经常问我如何使用Couchbase 2.0“版本化”文档。 简短的答案是:客户端和服务器没有公开这种功能,但是很容易实现。
在本文中,我将使用一种基本方法,您将能够根据您的业务需求对其进行扩展。
设计
要做的第一件事是选择如何“存储/组织”文档的版本,为此您有不同的设计:
- 将文档版本复制到新文档中
- 将文档版本复制到嵌入式文档列表中
- 存储已更改为嵌入式元素(或新文档)的属性列表
- 储存“三角洲”
- …
您将必须根据您的应用程序要求(业务逻辑,数据集的大小,…)选择设计。 对于本文,让我们使用一种最简单的方法:使用以下密钥规则为每个版本创建新文档:
- 当前版本是一个简单的密钥/文档,密钥没有更改。
- 版本是文档的副本,并且版本号已添加到密钥中。
看起来像:
当前版本 | 我的钥匙 |
版本1 | mykey :: v1 |
版本2 | mykey :: v2 |
… | … |
通过这种方法,由于密钥没有更改,因此现有应用程序将始终使用文档的当前版本。 但是这种方法创建的新文档将由现有视图索引。
例如,在Beer Sample应用程序中,以下视图用于按名称列出啤酒:
function (doc, meta) {
if(doc.type && doc.type == "beer") {
emit(doc.name);
}
}
“支持”版本控制非常简单,而不会影响现有代码(视图本身除外)。 新视图需要发出键,其值仅适用于文档的当前版本。 这是新的视图代码:
function (doc, meta) {
if(doc.type && doc.type == "beer" && (meta.id).indexOf("::v") == -1 ) {
emit(doc.name);
}
}
进行此更改后,使用此视图的现有应用程序将继续以相同的行为工作。
实施版本控制
基于此设计,当应用程序需要对文档进行版本控制时,应发生以下逻辑:
- 获取文档的当前版本
- 增加版本号(例如,使用另一个密钥维护每个文档的版本号)
- 使用新密钥“ mykey :: v1”创建版本
- 保存文档当前版本
让我们看一下Java中的代码
Object obj = client.get(key);
if (obj != null) {
// get the next version, create or use the key: mykey_version
long version = client.incr(key + "_version", 1, 1);
String keyForVersion = key + "::v" + version; // mykey::v1
try {
client.set(keyForVersion, obj).get();
} catch (Exception e) {
logger.severe("Cannot save version "+ version + " for key "+ key +" - Error:"+ e.getMessage() );
}
}
client.set(key, value);
是不是很简单?
应用程序可以使用密钥访问文档,但也可以获得一个版本或所有版本的列表,这是创建密钥很有趣的原因之一(
mykey_version),还可以使用它删除文档和相关版本。
根据前面的注释,删除操作如下所示:
Object obj = client.get(key);
// need to delete all the version first
Object vObject = this.get(key + "_version");
if (vObject != null) {
long biggerVersion = Long.parseLong((String) vObject);
try {
// delete all the versions
for (int i = 1; i <= biggerVersion; i++) {
String versionKey = key + "::v" + i;
client.delete(versionKey).get();
}
// delete the counter
client.delete(key + "_version").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
client.delete(key);
使用版本控制
例如,我在GitHub https://github.com/tgrall/couchbase-how-to-versioning上创建了一个小型库,该库扩展了Couchbase Client并覆盖了一些操作:设置,替换和删除。 (基本的:没有TLL,没有耐用性)正如我之前所说的,这只是一个例子。
编译安装
git clone https://github.com/tgrall/couchbase-how-to-versioning.git
cd how-to-versioning
mvn clean install
然后将此库(除了Couchbase Java Client)添加到您的项目中,例如在pom.xml中
...
com.couchbase.howtos
couchbase-how-to-versioning
1.0-SNAPSHOT
couchbase
couchbase-client
1.1.8
...
编写您的应用程序
创建一个文档并对其进行版本控制:
List uris = new LinkedList();
uris.add(URI.create("http://127.0.0.1:8091/pools"));
CouchbaseClientWithVersioning client = null
try {
client = new CouchbaseClientWithVersioning(uris, "default", "");
String key = "key-001";
client.set(key, "This is the original version");
System.out.printf("Original '%s' .\n", client.get(key));
client.set(key, "This is a new version", true); // create a new version
System.out.printf("Current Version '%s' .\n", client.get(key));
System.out.printf("Version 1 '%s' .\n", client.get(key, 1));
client.set(key, "This is another version", true); // create a new version
System.out.printf("All versions %s .\n", client.getAllVersions(key));
client.deleteVersion(key, 1); // create a new version
System.out.printf("All versions %s (after delete 1 version).\n", client.getAllVersions(key));
client.delete(key); // create a new version
System.out.printf("All versions %s (after delete the main key).\n", client.getAllVersions(key));
} catch (Exception e) {
e.printStackTrace();
}
if (client !=null) {
client.shutdown();
}
快速说明:
- 第5行:应用程序使用扩展的CouchbaseClientWithVersioning类,而不是使用CouchbaseClient。
- 第7行:创建一个新条目
- 第9行:创建新版本,布尔值设置为“ true”将强制对文档进行版本控制
- 应用程序使用其他方法,例如获取特定版本(第11行),获取所有版本(第13行),删除特定版本(第14行),最后删除密钥和所有版本(第16行)。
因此,使用这种方法,开发人员可以显式地控制何时创建版本,因为他必须在set操作中添加布尔参数。 在这个小的示例库中,还可以进行自动版本控制,在这种情况下,所有set和replace调用都将创建一个版本,以实现开发人员只需要调用setAutoVersioning(true)方法。 就像是:
client = new CouchbaseClientWithVersioning(uris, "default", "");
client.setAutomaticVersionning(true);
通过这种方法,您可以以最小的代码更改为应用程序提供版本控制。 您可以在Beer Sample应用程序中对其进行测试,只是不要忘了更改上面作为documenter的视图以仅返回
文件的当前版本。
结论
如您所见,在Couchbase中进行版本控制并不那么复杂,但这是应用程序必须根据其要求和约束来完成的。 您有许多不同的解决方案,这些选项都不是所有用例的完美选择。
在这个特定的示例代码中,我正在使用一个简单的设计,在该设计中,我为每个版本创建文档的副本。 同样使用这种方法,有趣的是,您可以对“任何内容”进行版本控制,不仅可以对JSON文档进行版本化,还可以对任何值进行版本化。 就像我之前说的,这是一种可能的方法,并且像任何设计一样,它对应用程序或数据库(在这种情况下,大多数数据库)都有一些影响:
- 增加键和文件的数量
- 两倍或更多的操作数,例如在更新文档时,应用程序需要获取当前值,创建版本,保存当前版本。
- 添加新版本和增加版本号时的一致性管理(创建新版本,删除版本和计数器时需要处理错误……)
许多功能可以轻松添加到此,例如:
- 限制为特定数量的版本,
- 仅启用replace()操作的版本控制
- 在JSON文档中添加有关版本的特定属性(例如版本日期)
- …。
如果您在Couchbase应用程序中使用版本控制,请随时发表评论或写一篇简短的文章来描述您的操作方式。
翻译自: https://www.javacodegeeks.com/2013/07/how-to-implement-document-versioning-with-couchbase.html