如何使用Couchbase实现文档版本控制

贡可人
2023-12-01

介绍

开发人员经常问我如何使用Couchbase 2.0“版本化”文档。 简短的答案是:客户端和服务器没有公开这种功能,但是很容易实现。

在本文中,我将使用一种基本方法,您将能够根据您的业务需求对其进行扩展。

设计

要做的第一件事是选择如何“存储/组织”文档的版本,为此您有不同的设计:

  • 将文档版本复制到新文档中
  • 将文档版本复制到嵌入式文档列表中
  • 存储已更改为嵌入式元素(或新文档)的属性列表
  • 储存“三角洲”

您将必须根据您的应用程序要求(业务逻辑,数据集的大小,…)选择设计。 对于本文,让我们使用一种最简单的方法:使用以下密钥规则为每个版本创建新文档:

  1. 当前版本是一个简单的密钥/文档,密钥没有更改。
  2. 版本是文档的副本,并且版本号已添加到密钥中。

看起来像:

当前版本 我的钥匙
版本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);
    }
}

进行此更改后,使用此视图的现有应用程序将继续以相同的行为工作。

实施版本控制

基于此设计,当应用程序需要对文档进行版本控制时,应发生以下逻辑:

  1. 获取文档的当前版本
  2. 增加版本号(例如,使用另一个密钥维护每个文档的版本号)
  3. 使用新密钥“ mykey :: v1”创建版本
  4. 保存文档当前版本

让我们看一下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

 类似资料: