Java CouchDB/Couchbase/MongoDB事务模拟?

Java CouchDB/Couchbase/MongoDB事务模拟?,java,spring,mongodb,transactions,couchdb,Java,Spring,Mongodb,Transactions,Couchdb,我以前从未使用过CouchDB/MongoDB/Couchbase,我正在为我的应用程序评估它们。总的来说,它们似乎是我想使用的一项非常有趣的技术。然而,来自RDBMS的背景,我对缺少事务感到困扰。但同时,考虑到数据的组织方式,我知道在RDBMS中,对事务的需求将大大减少 也就是说,我有以下要求,不确定是否/如何使用NoSQL DB 我有一份客户名单 每个客户端可以有多个文件 每个文件必须是该特定客户端的顺序编号 考虑到RDBMS,这将是相当简单的。一个表用于客户端,一个或多个表用于文件。在客户

我以前从未使用过CouchDB/MongoDB/Couchbase,我正在为我的应用程序评估它们。总的来说,它们似乎是我想使用的一项非常有趣的技术。然而,来自RDBMS的背景,我对缺少事务感到困扰。但同时,考虑到数据的组织方式,我知道在RDBMS中,对事务的需求将大大减少

也就是说,我有以下要求,不确定是否/如何使用NoSQL DB

我有一份客户名单 每个客户端可以有多个文件 每个文件必须是该特定客户端的顺序编号 考虑到RDBMS,这将是相当简单的。一个表用于客户端,一个或多个表用于文件。在客户机表中,保留最后一个filenumber的计数器,并在将新记录插入文件表时递增1。将所有内容包装在事务中,您就可以确信存在不一致性。见鬼,为了安全起见,我甚至可以在clientId、filenumber索引上设置一个唯一的约束,以确保客户端永远不会使用两次相同的filenumber


如何在MongoDB或CouchDB/base中实现类似的功能?甚至可行吗?我一直在读关于两阶段提交的书,但我似乎不知道在这种情况下如何工作。Spring/Java中是否有提供两阶段提交的东西可以与这些DBs一起使用,或者它是否需要自定义代码?

是的,您可以使用适当的方法对MongoDB和Couchbase/CouchDB执行相同的操作

首先,在MongoDB中,您有唯一的索引,这将帮助您确保部分问题: -

您还可以使用一些模式来正确实现顺序: -

您有许多实现跨文档/集合事务的选项,您可以在这篇博文中找到一些关于这方面的好信息: 此处详细记录了2阶段提交:

既然你在谈论Couchbase,你也可以在这里找到一些模式:

是的,您可以使用适当的方法对MongoDB和Couchbase/CouchDB执行相同的操作

首先,在MongoDB中,您有唯一的索引,这将帮助您确保部分问题: -

您还可以使用一些模式来正确实现顺序: -

您有许多实现跨文档/集合事务的选项,您可以在这篇博文中找到一些关于这方面的好信息: 此处详细记录了2阶段提交:

既然你在谈论Couchbase,你也可以在这里找到一些模式:
默认情况下,Couchdb是事务性的。couchdb中的每个文档都包含一个_rev键。对文档的所有更新都是根据此_revkey执行的:-

获取文档。 使用_rev属性发送更新。 如果更新成功,则您已更新文档的最新版本 如果更新失败,文档不是最新的。重复步骤1-3。 查看更详细的解释

有一个银行示例,显示如何在couchdb中完成交易

还有本文演示了couchdb中的事务

无论如何,所有这些链接中的共同主题是,如果您遵循couchdb模式,针对a_rev进行更新,那么您的数据库中就不会有不一致的状态

见鬼,为了安全起见,我甚至可以在clientId、filenumber索引上设置一个唯一的约束,以确保客户端永远不会使用两次相同的filenumber

所有couchdb文档都是唯一的,因为两个文档中的_id字段不能相同。查看

这很简单:在CouchDB数据库中,每个文档都必须有一个唯一的_id字段。如果您需要数据库中的唯一值,只需将它们分配给文档的_id字段,CouchDB就会为您强制执行唯一性

不过有一个警告:在分布式情况下,当您运行多个接受写请求的CouchDB节点时,只能保证每个节点或CouchDB之外的唯一性。CouchDB将允许将两个相同的ID写入两个不同的节点。在复制时,CouchDB将检测冲突并相应地标记文档

根据评论进行编辑

如果希望在成功插入另一个文档的基础上增加一个文档中的字段

在这种情况下,可以使用单独的文档。插入文档后,等待成功响应。然后添加另一个文档,如

{u-id:'some-u-id','count':1}

使用此功能,您可以设置一个map reduce视图,该视图只计算这些文档的结果,并且您有一个更新计数器。您所做的只是插入一个新文档以反映成功的插入,而不是为更新更新更新单个文档

我总是以一个失败的文件插入导致数据库处于不一致的状态而告终,特别是当另一个客户端成功插入时 同时删除一个文件

好的,我已经描述了如何对单独的文档进行更新,但即使在更新单个文档时,如果您:

插入新文件 当couchdb发出成功消息->尝试更新计数器时。 为什么会这样

这是因为当您尝试更新更新文档时,必须提供一个_rev字符串。您可以将_rev视为文档的一个本地州。考虑这种情况:-< /P> 您已阅读要更新的文档。 您可以更改一些字段。 同时,另一个请求已经更改了原始文档。这意味着该文档现在有一个新的_rev 但是您请求couchdb使用您在步骤1中读取的过时版本更新文档。 Couchdb将生成一个异常。 您再次阅读文档,获取最新版本并尝试更新它。 因此,如果您这样做,您将始终必须根据文档的最新版本进行更新。我希望这能让事情更清楚一点

注:


正如Daniel所指出的,_rev规则不适用于批量更新。

Couchdb在默认情况下是事务性的。couchdb中的每个文档都包含一个_rev键。对文档的所有更新都是根据此_revkey执行的:-

获取文档。 使用_rev属性发送更新。 如果更新成功,则您已更新文档的最新版本 如果更新失败,文档不是最新的。重复步骤1-3。 查看更详细的解释

有一个银行示例,显示如何在couchdb中完成交易

还有本文演示了couchdb中的事务

无论如何,所有这些链接中的共同主题是,如果您遵循couchdb模式,针对a_rev进行更新,那么您的数据库中就不会有不一致的状态

见鬼,为了安全起见,我甚至可以在clientId、filenumber索引上设置一个唯一的约束,以确保客户端永远不会使用两次相同的filenumber

所有couchdb文档都是唯一的,因为两个文档中的_id字段不能相同。查看

这很简单:在CouchDB数据库中,每个文档都必须有一个唯一的_id字段。如果您需要数据库中的唯一值,只需将它们分配给文档的_id字段,CouchDB就会为您强制执行唯一性

不过有一个警告:在分布式情况下,当您运行多个接受写请求的CouchDB节点时,只能保证每个节点或CouchDB之外的唯一性。CouchDB将允许将两个相同的ID写入两个不同的节点。在复制时,CouchDB将检测冲突并相应地标记文档

根据评论进行编辑

如果希望在成功插入另一个文档的基础上增加一个文档中的字段

在这种情况下,可以使用单独的文档。插入文档后,等待成功响应。然后添加另一个文档,如

{u-id:'some-u-id','count':1}

使用此功能,您可以设置一个map reduce视图,该视图只计算这些文档的结果,并且您有一个更新计数器。您所做的只是插入一个新文档以反映成功的插入,而不是为更新更新更新单个文档

我总是以一个失败的文件插入导致数据库处于不一致的状态而告终,特别是当另一个客户端同时成功插入文件时

好的,我已经描述了如何对单独的文档进行更新,但即使在更新单个文档时,如果您:

插入新文件 当couchdb发出成功消息->尝试更新计数器时。 为什么会这样

这是因为当您尝试更新更新文档时,必须提供一个_rev字符串。您可以将_rev视为文档的一个本地州。考虑这种情况:-< /P> 您已阅读要更新的文档。 您可以更改一些字段。 同时,另一个请求已经更改了原始文档。这意味着该文档现在有一个新的_rev 但是您请求couchdb使用您在步骤1中读取的过时版本更新文档。 Couchdb将生成一个异常。 您再次阅读文档,获取最新版本并尝试更新它。 因此,如果您这样做,您将始终必须根据文档的最新版本进行更新。我希望这能让事情更清楚一点

注:


正如Daniel所指出的,_rev规则不适用于批量更新。

Couchdb默认是事务性的。-只是澄清一下…这是每个文件。不跨越多个文档。如果验证处理程序无效,您可以将批量更新视为一个单元,但这不是一个事务。我以前读过原子银行转账文章,虽然使用了,但它们不处理需要保留准确计数的情况。如果你
ant要在成功插入另一个文档的基础上增加一个文档中的字段,我无法看到银行转账示例如何工作。无论我如何构造它,我总是会遇到这样的情况,即文件插入失败会使数据库处于不一致的状态-尤其是在另一个客户端同时成功插入文件的情况下。Couchdb在默认情况下是事务性的。-只是澄清一下…这是每个文件。不跨越多个文档。如果验证处理程序无效,您可以将批量更新视为一个单元,但这不是一个事务。我以前读过原子银行转账文章,虽然使用了,但它们不处理需要保留准确计数的情况。如果您希望在成功插入另一个文档的基础上增加一个文档中的字段,我看不出银行转账示例是如何工作的。无论我如何构造它,我总是会遇到这样的情况:文件插入失败会使数据库处于不一致的状态,特别是另一个客户端同时成功插入文件。我已经读过关于两阶段提交的内容,但我仍然不知道它在这里的应用。如果我有一个线程,我可以看到它工作,但如果我有多个线程,我不能保证原子性-即线程2可以在线程1完成之前完全执行,如果第一个线程失败,但第二个线程成功,文件号/计数器将不正确。除非我误解了如何正确地进行两阶段提交,否则我不这么认为。我已经读过关于两阶段提交的文章,但我仍然不知道它在这里如何应用。如果我有一个线程,我可以看到它工作,但如果我有多个线程,我不能保证原子性-即线程2可以在线程1完成之前完全执行,如果第一个线程失败,但第二个线程成功,文件号/计数器将不正确。除非我误解了如何正确地进行两阶段承诺,否则我不这么认为。