Учебники

MongoDB — Атомные Операции

MongoDB не поддерживает атомарные транзакции с несколькими документами . Тем не менее, он обеспечивает атомарные операции над одним документом. Таким образом, если документ имеет сто полей, оператор update либо обновит все поля, либо ни одного, следовательно, сохраняя атомарность на уровне документа.

Данные модели для атомарных операций

Рекомендуемый подход к сохранению атомарности заключается в хранении всей связанной информации, которая часто обновляется вместе в одном документе с использованием встроенных документов . Это позволит убедиться, что все обновления для одного документа являются атомарными.

Рассмотрим следующий документ о продуктах —

{
   "_id":1,
   "product_name": "Samsung S3",
   "category": "mobiles",
   "product_total": 5,
   "product_available": 3,
   "product_bought_by": [
      {
         "customer": "john",
         "date": "7-Jan-2014"
      },
      {
         "customer": "mark",
         "date": "8-Jan-2014"
      }
   ]
}

В этом документе мы включили информацию о клиенте, который покупает продукт, в поле product_bought_by . Теперь, когда новый клиент покупает продукт, мы сначала проверяем, доступен ли продукт, используя поле product_available . Если доступно, мы уменьшим значение поля product_available, а также вставим встроенный документ нового клиента в поле product_bought_by. Мы будем использовать команду findAndModify для этой функциональности, потому что она ищет и обновляет документ одновременно.

>db.products.findAndModify({ 
   query:{_id:2,product_available:{$gt:0}}, 
   update:{ 
      $inc:{product_available:-1}, 
      $push:{product_bought_by:{customer:"rob",date:"9-Jan-2014"}} 
   }    
})

Наш подход к встроенному документу и использованию запроса findAndModify гарантирует, что информация о покупке продукта обновляется только в том случае, если продукт доступен. И вся эта транзакция, находящаяся в одном запросе, является атомарной.

В отличие от этого рассмотрим сценарий, в котором мы могли бы отдельно хранить информацию о доступности продукта и информацию о том, кто его купил. В этом случае мы сначала проверим, доступен ли продукт, используя первый запрос. Затем во втором запросе мы обновим информацию о покупке. Однако, возможно, что между выполнением этих двух запросов какой-то другой пользователь приобрел продукт, и он больше не доступен. Не зная этого, наш второй запрос обновит информацию о покупке на основе результата нашего первого запроса. Это сделает базу данных несовместимой, потому что мы продали продукт, который недоступен.