我意识到,就其本质而言,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
的文档的ObjectIdtransaction
3:执行更新。对于每个受影响的文档:
- 将该文档中的任何受影响的字段替换为
data_new
值 - 设置
change_complete
为true
4:将transaction
文档设置status
为true
(因为所有数据都已成功修改)
5:对于受交易影响的每个文档,做一些清理:
- 删除
data_old
anddata_new
,因为它们不再需要 - 设置
lock_status
为false
(解锁文档)
6:删除transaction
步骤1中设置的文档(或按照建议,将其标记为完成)
我认为这在逻辑上是这样工作的,如果它在任何时候失败,所有数据都可以回滚或者可以继续事务(取决于你想要做什么)。显然所有回滚/恢复/等。由应用程序而不是数据库执行,通过使用transaction
具有该 transaction_id 的其他集合中的文档和文档。
我错过或忽略了这个逻辑中的任何明显错误吗?有没有更有效的方法(例如,减少数据库的写入/读取)?