- PVSM.RU - https://www.pvsm.ru -
MongoDB — замечательная база данных, которая становиться все популярнее в последнее время. Все больше людей с SQL опытом начинают её использовать, и один и первых вопросов, который у них возникает: MongoDB transactions? [1].
Если поверить людям со stackoverflow, то все плохо.
MongoDB doesn't support complex multi-document transactions. If that is something you absolutely need it probably isn't a great fit for you.
If transactions are required, perhaps NoSQL is not for you. Time to go back to ACID relational databases.
MongoDB does a lot of things well, but transactions is not one of those things.
Но мы не поверим и реализуем полноценные транзакции (ACID и lock-free). Ниже будет рассказ о том, как эти транзакции работают, а тем, кому не терпиться посмотреть код — добро пожаловать на GitHub [2] (осторожно, java).
В отличии от многих других NoSQL решений, MongoDB поддерживает compare-and-set. Именно поддержка CAS позволяет добавить ACID транзакции. Если вы используете любое другое NoSQL хранилище с поддержкой CAS (например, HBase, Project Voldemort или ZooKeeper), то описанный подход можно применить и там.
Что такое CAS
Это механизм, который гарантирует отказ в изменении объекта, если с момента последнего чтения объект был изменен другим клиентом. Знакомый всем пример - система контроля версий, которая откажет вам в коммите, если ваш коллега успел закомититься раньше.
Собственно все объекты, которые мы хотим изменять в транзакции должны быть под защитой CAS, это это влияет на модель данных. Допустим мы моделируем работу банка, ниже приведена модель счета как с защитой, так и без неё, надеюсь из этого ясно как нужно изменить остальные.
Беззащитные | Подзащитные | |
Модель |
|
|
Изменение данных |
|
|
Далее, я не буду акцентировать внимание на том, что у объекта есть версия, и что любое изменение объекта проходит с учетом его версии, но это нужно помнить и понимать, что любое изменение объекта может вылетить с ошибкой из-за конкурентного доступа.
На самом деле добавление версии — это не все изменения, которые нужно провести над моделью, чтобы она поддерживала транзакции, полностью измененная модель выглядит так:
{
_id : ObjectId(".."),
version : 0,
value : {
name : "gov",
balance : 600
},
updated : null,
tx : null
}
Добавились поля — updated и tx. Это служебные данные, которые используются в процессе транзакции. По структуре updated совпадает с value, по смыслу — это изменная версия объекта, которая превратиться в value, если транзакция пройдет; tx — это объект класса ObjectId — foreign key для _id объекта, представляющий транзакцию. Объект представляющий транзакцию так же находиться под защитой CAS.
Объяснить алгоритм просто, объяснить его так, что его корректность была очевидна, сложнее; поэтому придеться то, что некоторыми сущностями я буду оперировать до того, как их определю.
Ниже идут верные утверждения, определения и свойства из которых позже будет составлен алгоритм.
Чистое состояние описывает объект после успешной транзакции: value содержит данные, а upated и tx — null.
Грязное незакомиченное состояние описывает объект в момент транзакции, updated содержит новую версию, а tx — _id объекта представляющего транзакцию, этот объект существует.
Грязное закомиченное состояние описывает объект после успешной транзакции, но которя упала до того, как успела подчистить за собой, updated содержит новую версию, tx — _id объекта представляющего транзакцию, но сам объект уже удален.
Для тех кому теперь не очивидна корректность, домашнее задание — проверить, что выполняются все свойства и утверждения, а затем используя их доказать ACID ☺
Мы добавили в MongoDB транзакции, а ребята со stackoverflow оказались не компетентны. На самом деле у наших транзакций есть несколько свойств, о которых нужно помнить:
Автор: shai_xylyd
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/16678
Ссылки в тексте:
[1] MongoDB transactions?: http://stackoverflow.com/questions/2655251/mongodb-transactions
[2] GitHub: https://github.com/rystsov/mongodb-transaction-example
[3] см. w: http://www.mongodb.org/display/DOCS/getLastError+Command#getLastErrorCommand-%7B%7Bw%7D%7D
Нажмите здесь для печати.