Я понимаю, что MongoDB по своей природе не поддерживает и, вероятно, никогда не будет поддерживать подобные транзакции. Тем не менее, я обнаружил, что мне нужно использовать их несколько ограниченным образом, поэтому я придумал следующее решение, и мне интересно: - это лучший способ сделать это, и может ли это улучшить? (прежде чем я пойду и реализую его в своем приложении!)
Очевидно, что транзакция контролируется через приложение (в моем случае - веб-приложение Python). Для каждого документа в этой транзакции (в любой коллекции) добавляются следующие поля:
'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
в ObjectId документаtransaction
, который мы только что создали.
3: Выполните обновление. Для каждого документа:
- Заменить любые затронутые поля в этом документе значениями
data_new
- Установите
change_complete
вtrue
4: Установите transaction
document status
на true
(так как все данные были успешно изменены)
5: Для каждого документа, затронутого транзакцией, выполните некоторую очистку:
- удалите
data_old
иdata_new
, поскольку они больше не нужны - установите
lock_status
вfalse
(чтобы разблокировать документ)
6: Удалите документ transaction
, настроенный на шаге 1 (или, как предлагается, отметьте его как завершенное)
Я думаю, что логически работает таким образом, что если он сбой в любой момент, все данные могут быть либо отброшены, либо транзакция может быть продолжена (в зависимости от того, что вы хотите сделать). Очевидно, что все откаты/восстановление/и т.д. выполняется приложением, а не базой данных, используя документы transaction
и документы в других коллекциях с этой транзакцией_id.
Есть ли вопиющая ошибка в этой логике, которую я пропустил или пропустил? Есть ли более эффективный способ обойти это (например, меньше писать/читать из базы данных)?