我意识到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
此外,还有一个transaction
集合,用于存储详细说明正在进行的每个事务的文档。他们看起来像:
{
'_id': ObjectId,
'date_added': datetime,
'status': bool (true = all changes successful, false = in progress),
'collections': array of collection names involved in the transaction
}
这是这个过程的逻辑。希望它以这样的方式工作:如果它被中断,或者以其他方式失败,它可以正常回滚。
1:设置transaction
文档
2:对于受此次交易影响的每个文档:
lock_status
设置为true
(以“锁定”文档不被修改)data_old
和data_new
设置为旧值和新值change_complete
设为false
transaction_id
设置为我们刚刚制作的transaction
文档的ObjectId 3:执行更新。对于每个受影响的文件:
data_new
值change_complete
设为true
4:将transaction
文档的status
设置为true
(因为所有数据都已成功修改)
5:对于受交易影响的每个文档,请进行一些清理:
data_old
和data_new
,因为不再需要lock_status
设置为false
(解锁文档) 6:删除步骤1中设置的transaction
文档(或按照建议,将其标记为完成)
我认为逻辑上的工作方式是,如果它在任何时候都失败,所有数据都可以回滚或者事务可以继续(取决于你想做什么)。显然所有的回滚/恢复/等。由应用程序而不是数据库执行,使用transaction
文档和其他集合中具有该transaction_id的文档。
我错过或忽略了这个逻辑中是否有任何明显的错误?是否有更有效的方法(例如,从数据库中减少写入/读取)?
答案 0 :(得分:11)
作为通用响应,MongoDB上的多文档提交可以作为两个阶段提交来执行,这些提交在手册中有详细记录(参见:http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/)。
本手册建议的模式简要介绍如下:
transactions
集合,其中包括目标文档,源文档,值和状态< / em>(交易)initial
作为state
state
更新为pending
committed
done
另外:
state
值canceling
您的实施的一些具体说明:
lock_status
,data_old
,data_new
等字段添加到源/目标文档中。这些应该是事务的属性,而不是文档本身。 DBref
s:http://www.mongodb.org/display/DOCS/Database+References done
似乎是一个更好的主意,因为这允许您稍后调试并找出已执行的事务类型。我很确定你也不会耗尽磁盘空间(为此也有解决方案)。答案 1 :(得分:3)
MongoDB 4.0添加了对多文档ACID事务的支持。
Java示例:
try (ClientSession clientSession = client.startSession()) {
clientSession.startTransaction();
collection.insertOne(clientSession, docOne);
collection.insertOne(clientSession, docTwo);
clientSession.commitTransaction();
}
答案 2 :(得分:0)
MongoDB 4.0正在添加(多集合)多文档事务:link