我知道MongoDB的本质不支持这种类型的事务,也许永远不会支持。但是,在某种程度上我发现自己确实需要以一种有限制的方式使用它们,因此我想出了以下解决方案,并且我想知道:是否这是最佳实践,是否可以改进?(在我将其应用于我的应用程序之前!)
显然,事务是通过应用程序控制的(在我的情况下,是一个Python Web应用程序)。 为了每个文档(在任何集合中)都添加以下字段来控制事务:
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_id的transaction文档和其他集合中的文档进行。是否有我忽视或忽略的逻辑上的显著错误?是否有更有效的方法(例如,从数据库中少写/读)?
显然,事务是通过应用程序控制的(在我的情况下,是一个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_id的transaction文档和其他集合中的文档进行。是否有我忽视或忽略的逻辑上的显著错误?是否有更有效的方法(例如,从数据库中少写/读)?
change_complete
更新为true
,该怎么办?你如何确保这种情况不会发生? - jsalonen