我可以在 CouchDB 中进行事务和锁定吗? [英] Can I do transactions and locks in CouchDB?

查看:32
本文介绍了我可以在 CouchDB 中进行事务和锁定吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要做事务(开始、提交或回滚)、锁(选择更新).如何在文档模型数据库中做到这一点?

I need to do transactions (begin, commit or rollback), locks (select for update). How can I do it in a document model db?

情况是这样的:

  • 我想经营一个拍卖网站.
  • 我也想如何直接购买.
  • 在直接购买中,我必须减少商品记录中的数量字段,但前提是数量大于零.这就是我需要锁和事务的原因.
  • 如果没有锁和/或事务,我不知道如何解决这个问题.

我可以用 CouchDB 解决这个问题吗?

Can I solve this with CouchDB?

推荐答案

没有.CouchDB 使用乐观并发"模型.用最简单的术语来说,这只是意味着您将文档版本与更新一起发送,如果当前文档版本与您发送的内容不匹配,CouchDB 会拒绝更改.

No. CouchDB uses an "optimistic concurrency" model. In the simplest terms, this just means that you send a document version along with your update, and CouchDB rejects the change if the current document version doesn't match what you've sent.

这看起来很简单,真的.您可以为 CouchDB 重构许多基于常规事务的场景.不过,在学习 CouchDB 时,您确实需要放弃您的 RDBMS 领域知识.从更高的层次解决问题是有帮助的,而不是试图将 Couch 塑造成一个基于 SQL 的世界.

It's deceptively simple, really. You can reframe many normal transaction based scenarios for CouchDB. You do need to sort of throw out your RDBMS domain knowledge when learning CouchDB, though. It's helpful to approach problems from a higher level, rather than attempting to mold Couch to a SQL based world.

跟踪库存

您概述的问题主要是库存问题.如果您有一个描述项目的文档,并且它包含一个可用数量"字段,您可以像这样处理并发问题:

The problem you outlined is primarily an inventory issue. If you have a document describing an item, and it includes a field for "quantity available", you can handle concurrency issues like this:

  1. 检索文档,记下 CouchDB 发送的 _rev 属性
  2. 如果数量字段大于零,则减少数量字段
  3. 使用 _rev 属性将更新后的文档发回
  4. 如果 _rev 与当前存储的号码匹配,则完成!
  5. 如果有冲突(当 _rev 不匹配时),检索最新的文档版本
  1. Retrieve the document, take note of the _rev property that CouchDB sends along
  2. Decrement the quantity field, if it's greater than zero
  3. Send the updated document back, using the _rev property
  4. If the _rev matches the currently stored number, be done!
  5. If there's a conflict (when _rev doesn't match), retrieve the newest document version

在这种情况下,需要考虑两种可能的故障情况.如果最新文档版本的数量为 0,则您可以像在 RDBMS 中一样处理它,并提醒用户他们实际上无法购买他们想要购买的东西.如果最新文档版本的数量大于 0,您只需使用更新的数据重复操作,然后从头开始.这迫使您比 RDBMS 做更多的工作,并且如果有频繁的、冲突的更新,可能会有点烦人.

In this instance, there are two possible failure scenarios to think about. If the most recent document version has a quantity of 0, you handle it just like you would in a RDBMS and alert the user that they can't actually buy what they wanted to purchase. If the most recent document version has a quantity greater than 0, you simply repeat the operation with the updated data, and start back at the beginning. This forces you to do a bit more work than an RDBMS would, and could get a little annoying if there are frequent, conflicting updates.

现在,我刚刚给出的答案假定您将在 CouchDB 中以与在 RDBMS 中相同的方式执行操作.我可能会以不同的方式处理这个问题:

Now, the answer I just gave presupposes that you're going to do things in CouchDB in much the same way that you would in an RDBMS. I might approach this problem a bit differently:

我会从包含所有描述符数据(名称、图片、描述、价格等)的主产品"文档开始.然后,我会为每个特定实例添加一个库存单"文档,其中包含 product_keyclaimed_by 字段.如果您要销售一种锤子模型,并且有 20 个要出售,那么您可能有带有 hammer-1hammer-2 等键的文档,以代表每个可用的锤子.

I'd start with a "master product" document that includes all the descriptor data (name, picture, description, price, etc). Then I'd add an "inventory ticket" document for each specific instance, with fields for product_key and claimed_by. If you're selling a model of hammer, and have 20 of them to sell, you might have documents with keys like hammer-1, hammer-2, etc, to represent each available hammer.

然后,我将创建一个视图,该视图为我提供了可用锤子的列表,并带有一个可以让我查看总数"的 reduce 函数.这些完全是即兴的,但应该让您了解工作视图的外观.

Then, I'd create a view that gives me a list of available hammers, with a reduce function that lets me see a "total". These are completely off the cuff, but should give you an idea of what a working view would look like.

地图

function(doc) 
{ 
    if (doc.type == 'inventory_ticket' && doc.claimed_by == null ) { 
        emit(doc.product_key, { 'inventory_ticket' :doc.id, '_rev' : doc._rev }); 
    } 
}

这给了我一个可用票"的列表,按产品密钥.当有人想买一把锤子时,我可以抓住其中的一组,然后迭代发送更新(使用 id_rev)直到我成功申领一个(之前申领门票)会导致更新错误).

This gives me a list of available "tickets", by product key. I could grab a group of these when someone wants to buy a hammer, then iterate through sending updates (using the id and _rev) until I successfully claim one (previously claimed tickets will result in an update error).

减少

function (keys, values, combine) {
    return values.length;
}

这个 reduce 函数只返回无人认领的 inventory_ticket 物品的总数,因此您可以知道有多少锤子"可供购买.

This reduce function simply returns the total number of unclaimed inventory_ticket items, so you can tell how many "hammers" are available for purchase.

注意事项

对于您提出的特定问题,这个解决方案代表了大约 3.5 分钟的总思考时间.可能有更好的方法来做到这一点!也就是说,它确实大大减少了冲突更新,并减少了使用新更新来响应冲突的需要.在此模型下,您不会有多个用户尝试更改主要产品条目中的数据.在最坏的情况下,您将有多个用户试图索取一张票,如果您从您的视图中抓取了其中的几个,您只需转到下一张票并重试.

This solution represents roughly 3.5 minutes of total thinking for the particular problem you've presented. There may be better ways of doing this! That said, it does substantially reduce conflicting updates, and cuts down on the need to respond to a conflict with a new update. Under this model, you won't have multiple users attempting to change data in primary product entry. At the very worst, you'll have multiple users attempting to claim a single ticket, and if you've grabbed several of those from your view, you simply move on to the next ticket and try again.

参考:https://wiki.apache.org/couchdb/Frequently_asked_questions#How_do_I_use_transactions_with_CouchDB.3F

这篇关于我可以在 CouchDB 中进行事务和锁定吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆