本文介绍了MongoDB中的多集合,多文档“事务"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到,MongoDB本质上不会并且可能永远不会支持此类事务.但是,我发现我确实需要以某种有限的方式使用它们,因此我想出了以下解决方案,我想知道:这是最好的方法吗?需要改进吗?(在我将其应用到我的应用之前!)

I realise that MongoDB, by it's very nature, doesn't and probably never will support these kinds of transactions. However, I have found that I do need to use them in a somewhat limited fashion, so I've come up with the following solution, and I'm wondering: is this the best way of doing it, and can it be improved upon? (before I go and implement it in my app!)

很明显,交易是通过应用程序(在我的情况下是Python网络应用程序)控制的.对于此事务中的每个文档(在任何集合中),都会添加以下字段:

Obviously the transaction is controlled via the application (in my case, a Python web app). For each document in this transaction (in any collection), the following fields are added:

'lock_status': bool (true = locked, false = unlocked),
'data_old': dict (of any old values - current values really - that are being changed),
'data_new': dict (of values replacing the old (current) values - should be an identical list to data_old),
'change_complete': bool (true = the update to this specific document has occurred and was successful),
'transaction_id': ObjectId of the parent transaction

此外,还有一个transaction集合,该集合存储详细描述每个正在进行的交易的文档.它们看起来像:

In addition, there is a transaction collection which stores documents detailing each transaction in progress. They look like:

{
    '_id': ObjectId,
    'date_added': datetime,
    'status': bool (true = all changes successful, false = in progress),
    'collections': array of collection names involved in the transaction
}

这是流程的逻辑.希望它能以某种方式工作,如果它发生中断或以其他方式失败,则可以正确地回滚.

And here's the logic of the process. Hopefully it works in such a way that if it's interupted, or fails in some other way, it can be rolled back properly.

1 :设置transaction文档

2 :对于受此交易影响的每个文档:

2: For each document that is affected by this transaction:

  • lock_status设置为true(以锁定"文档以免其被修改)
  • data_olddata_new设置为旧值和新值
  • change_complete设置为false
  • transaction_id设置为我们刚刚制作的transaction文档的ObjectId
  • Set lock_status to true (to 'lock' the document from being modified)
  • Set data_old and data_new to their old and new values
  • Set change_complete to false
  • Set transaction_id to the ObjectId of the transaction document we just made

3 :执行更新.对于每个受影响的文件:

3: Perform the update. For each document affected:

  • data_new值替换该文档中所有受影响的字段
  • change_complete设置为true
  • Replace any affected fields in that document with the data_new values
  • Set change_complete to true

4 :将transaction文档的status设置为true(因为已成功修改所有数据)

4: Set the transaction document's status to true (as all data has been modified successfully)

5::对于受交易影响的每个文档,请进行一些清理:

5: For each document affected by the transaction, do some clean up:

  • 删除data_olddata_new,因为它们不再需要
  • lock_status设置为false(以解锁文档)
  • remove the data_old and data_new, as they're no longer needed
  • set lock_status to false (to unlock the document)

6 :删除步骤1中设置的transaction文档(或根据建议,将其标记为完成)

6: Remove the transaction document set up in step 1 (or as suggested, mark it as complete)

我认为在逻辑上以这样的方式工作:如果它在任何时候失败,则可以回滚所有数据或可以继续进行事务(取决于您要执行的操作).显然所有回滚/恢复/等.通过使用transaction文档以及具有该transaction_id的其他集合中的文档,由应用程序而不是数据库执行.

I think that logically works in such a way that if it fails at any point, all data can be either rolled back or the transaction can be continued (depending on what you want to do). Obviously all rollback/recovery/etc. is performed by the application and not the database, by using the transaction documents and the documents in the other collections with that transaction_id.

此逻辑中是否有我遗漏或忽略的明显错误?有没有更有效的解决方案(例如,更少的数据库读写操作)?

推荐答案

作为通用响应,可以将MongoDB上的多文档提交分为两个阶段提交,这在手册中已有详细介绍(请参见: http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/).

As a generic response multi-document commits on MongoDB can be performed as two phase commits, which have been somewhat extensively documented in the manual (See: http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/).

手册中建议的模式简要如下:

The pattern suggested by the manual is briefly to following:

  • 设置单独的transactions集合,其中包括目标文档源文档状态(在交易中)
  • 使用initial作为state
  • 创建新的交易对象
  • 开始进行交易,并将state更新为pending
  • 将交易应用于两个文档(目标,源)
  • 将交易状态更新为committed
  • 使用find来确定文档是否反映交易状态,如果可以,请将交易状态更新为done
  • Set up a separate transactions collection, that includes target document, source document, value and state (of the transaction)
  • Create new transaction object with initial as the state
  • Start making a transaction and update state to pending
  • Apply transactions to both documents (target, source)
  • Update transaction state to committed
  • Use find to determine whether documents reflect the transaction state, if ok, update transaction state to done

此外:

  • 您需要手动处理故障情况(未发生某些情况,如下所述)
  • 您基本上需要通过引入名称statecanceling
  • 来手动实施回滚
  • You need to manually handle failure scenarios (something didn't happen as described below)
  • You need to manually implement a rollback, basically by introducing a name state value canceling

一些具体的实施注意事项:

Some specific notes for your implementation:

  • 我不鼓励您将诸如lock_statusdata_olddata_new之类的字段添加到源/目标文档中.这些应该是交易的属性,而不是单据本身.
  • 为概括目标/源文档的概念,我认为您可以使用DBref s: http://www.mongodb.org/display/DOCS/Database+References
  • 我不喜欢在完成交易文件后删除它们的想法.将状态设置为done似乎是一个更好的主意,因为这使您以后可以调试并找出已执行的事务类型.我很确定您也不会用完磁盘空间(为此也有解决方案).
  • 在您的模型中,如何保证一切都按预期进行了更改?您是否以某种方式检查更改?
  • I would discourage you from adding fields like lock_status, data_old, data_new into source/target documents. These should be properties of the transactions, not the documents themselves.
  • To generalize the concept of target/source documents, I think you could use DBrefs: http://www.mongodb.org/display/DOCS/Database+References
  • I don't like the idea of deleting transaction documents when they are done. Setting state to done seems like a better idea since this allows you to later debug and find out what kind of transactions have been performed. I'm pretty sure you won't run out of disk space either (and for this there are solutions as well).
  • In your model how do you guarantee that everything has been changed as expected? Do you inspect the changes somehow?

这篇关于MongoDB中的多集合,多文档“事务"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 17:57