MongoDB中的多集合,多文档"事务"

joh*_*eth 14 transactions mongodb

我意识到MongoDB,就其本质而言,不会也可能永远不会支持这类交易.但是,我发现我确实需要以有限的方式使用它们,所以我想出了以下解决方案,我想知道:这是最好的方法,并且可以改进它?(在我去我的应用程序之前实现它!)

显然,事务是通过应用程序控制的(在我的例子中,是一个Python Web应用程序).对于此事务中的每个文档(在任何集合中),将添加以下字段:

'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
Run Code Online (Sandbox Code Playgroud)

此外,还有一个transaction集合,用于存储详细说明正在进行的每个事务的文档.他们看着像是:

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

这是这个过程的逻辑.希望它以这样的方式工作:如果它被中断,或者以其他方式失败,它可以正常回滚.

1:设置transaction文档

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

  • 设置lock_statustrue("锁定"文档不被修改)
  • 设置data_olddata_new他们的新旧价值观
  • 设置change_completefalse
  • 设置transaction_idtransaction我们刚刚创建的文档的ObjectId

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

  • 使用data_new值替换该文档中的所有受影响的字段
  • 设置change_completetrue

4:transaction文档设置statustrue(因为所有数据都已成功修改)

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

  • 删除data_olddata_new,因为他们不再需要
  • 设置lock_statusfalse(解锁文档)

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


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

我错过或忽略了这个逻辑中是否有任何明显的错误?是否有更有效的方法(例如,从数据库中减少写入/读取)?

jsa*_*nen 12

作为一般响应,MongoDB上的多文档提交可以作为两阶段提交来执行,这些提交已在手册中进行了大量记录(参见:http://docs.mongodb.org/manual/tutorial/perform-two-phase-提交/).

本手册建议的模式简要介绍如下:

  • 设置单独的transactions集合,包括目标文档,源文档,状态(事务)
  • 使用initialas 创建新的事务对象state
  • 开始制作交易并更新statepending
  • 将交易应用于两个文件(目标,来源)
  • 将事务状态更新为 committed
  • 使用find确定文档是否反映了事务状态,如果确定,则更新事务状态 done

此外:

  • 您需要手动处理故障情况(某些事情未发生,如下所述)
  • 您需要手动实现回滚,主要是通过引入名称statecanceling

您的实施的一些具体说明:

  • 我会从像添加字段气馁lock_status,data_old,data_new成源/目标文件.这些应该是事务的属性,而不是文档本身.
  • 为了概括目标/源文档的概念,我认为你可以使用DBrefs:http://www.mongodb.org/display/DOCS/Database+References
  • 我不喜欢在完成后删除交易文件的想法.设置状态done似乎是一个更好的主意,因为这允许您稍后调试并找出已执行的事务类型.我很确定你也不会耗尽磁盘空间(为此也有解决方案).
  • 在您的模型中,您如何保证所有内容都按预期更改?你以某种方式检查变化吗?


SAN*_*NN3 5

MongoDB 4.0添加了对多文档 ACID 事务的支持。

Java 示例:

try (ClientSession clientSession = client.startSession()) {
   clientSession.startTransaction();
   collection.insertOne(clientSession, docOne);
   collection.insertOne(clientSession, docTwo);
   clientSession.commitTransaction();
}
Run Code Online (Sandbox Code Playgroud)

请注意,它适用于副本集。您仍然可以拥有一个带有一个节点的副本集并在本地机器上运行它。