@kazmiruk

Как обойти отсутствие транзакций в MongoDB?

Есть проект, главная суть которого — электронная коммерция. Вся структура идеально укладывается в mongodb, учитывая ее безсхемность. Но есть проблемы с пониманием реализации транзакционности в этом проекте. Монго не поддерживает транзакции. Необходимо решить следующие задачи:
— передача денег от А к В с проверками и откатами;
— покупка товара (уходит со склада и приходит пользователю в заказы, причем так, чтобы 2 пользователя не купили последний товар со склада, а владелец товара не успел изменить цену, пока пользователь покупал (условно говоря лок на товар))
Перерыл интернет и нашел несколько решений этой проблемы:
1. Реализация двухфазного коммита на уровне приложения (из Cookbook mongoDB). Всем хорош способ, но уже для двух сущностей получается навороченные проверки, в которых легко запутаться и код получается совершенно неуниверсальным, так как откаты приходится делать вручную.
2. Перенос всего, что требует транзакции на РСУБД. Т. е. есть коллекция товар в монго и есть таблица склад, которая содержит id товара из монго и кол-во этого товара (упрощенно). Этот вариант отталкивает тем, что возникнет необходимость разбивать сущности на несколько частей и, мало того, хранить эти сущности в разных СУБД. Да и держать зоопарк СУБД под один проект кажется не самым верным решением.

Кто сталкивался с подобными проблемами и каким-либо образом решал ее — поделитесь опытом.
  • Вопрос задан
  • 7282 просмотра
Пригласить эксперта
Ответы на вопрос 3
— передача денег от А к В с проверками и откатами;

Просто не надо использовать mongodb для этого. Не получится. mongo написана для хранения не ценных данных, потери которых мало кого интересуют. Поэтому, например, mongo по-умолчанию сразу возвращает успех, не дожидаясь записи в базу.
— покупка товара (уходит со склада и приходит пользователю в заказы, причем так, чтобы 2 пользователя не купили последний товар со склада, а владелец товара не успел изменить цену, пока пользователь покупал (условно говоря лок на товар))

Это скорее всего можно сделать атомарными операциями. Но если надо, локи организуются с помощью поля «заблокирован до», уникального индекса на id товара и запросов вида
upsert(«объект с установленным полем времени блокировки», «время блокировки меньше текущего времени»)
Если лока еще нет, то он будет создан. Если лок есть но просрочен (захвативший его процесс упал), то запрос обновит такую запись. Если лок захвачен, то запрос попытается создать новый lock, но упадет из-за дубликата ключа в индексе.
Ответ написан
Комментировать
Juralis
@Juralis
Как я понимаю, mongodb тут хорошо именно в том ключе, что можно для разных типов товара задавать профильные конкретно для него свойства и не описывать их заранее. И есть некий набор свойств, присущий всем товарам (как количество, стоимость и т.д.). В этом смысле, вам действительно было бы удобнее убрать эти универсальные свойства в РСУБД и эта задача явно не для mongodb.
Сам не пользовался, но судя по анонсу PostgreSQL 9.2 поддерживает json field и возможно это подойдёт для такой задачи.
Но, похоже есть некоторые сложности с поиском по данным этого поля.
Вот, к примеру, вопрос (с решением) на stackoverflow:
stackoverflow.com/questions/10560394/how-do-i-query-using-fields-inside-the-new-postgresql-json-datatype
Ответ написан
Комментировать
Stdit
@Stdit
Да, двухфазные коммиты, хранение и проверка состояний транзакций или версий объектов (документов). MongoDB не предназначена для таких задач, это говорят даже сами разработчики. Это просто быстрое и масштабируемое хранилище оъектов произвольной структуры с гибким поиском. Используйте РСУБД. Как правильно заметил Juralis, тот же PostgreSQL имеет богатые и интересные возможности, такие как наследование таблиц, работа с массивами и другими нетипичными для SQL типами данных. Они могут оказаться подходящими под ваши задачи.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы