Может кто-нибудь объяснить, как это достигается в mongoDB?
Здесь есть несколько элементов для распаковки, но давайте начнем с базовых MongoDB многодокументных транзакций .
Если операции обновления выполняются внутри транзакционного сеанса, вторая операция обновления будет заблокирована до тех пор, пока первая транзакция не будет зафиксирована, прервана или истекла.См. Дополнительную информацию об этом поведении в MDBW18: как и когда использовать распределенные транзакции с несколькими документами
Например (на основе MongoDB v4.0.3), если у вас есть документ, как показано ниже:
{"person": "one", "balance": NumberDecimal(100)}
С операцией обновления, как показано ниже:
s1 = Mongo().startSession() ;
sessionFoo = s1.getDatabase("databaseName").collectionName;
s1.startTransaction();
var result = sessionFoo.update({"person":"one"}, {"$set":{"balance":120}});
// ...
s1.commitTransaction();
Если другая операция обновления (аналогичная описанной выше) произойдет до commitTransaction
, она получит TransientTransactionError
.Пример вывода ошибки:
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp(1540175676, 1),
"ok" : 0,
"errmsg" : "Unable to acquire lock '{7817449386782089629: Database, 899920359141007773}' within a max lock request timeout of '5ms' milliseconds.",
"code" : 24,
"codeName" : "LockTimeout",
В 9: 00: 02: 001 обновить $ 120 на учетную запись Person-1 в DB2
Как правило, вы этого не делаетеобновить до значения, но выполнить приращение события ( $ inc оператор ) значения.Таким образом, вместо:
var result = sessionFoo.update({"person":"one"}, {"$set":{"balance":120}});
Это будет:
var result = sessionFoo.update({"person":"one"}, {"$inc":{"balance":20}});
Чтобы расширить это, обычно для записей, связанных с финансами, вы хотите записывать события вместо состояния.См. Также Even Sourcing .Например, вместо ниже:
t1: balance 100
t2: balance 120
t3: balance 150
t4: balance 70
Где balance
представляет состояние баланса в момент времени t
.Это могут быть такие события, как:
t1: balance 100
t2: balance +20
t3: balance +30
t4: balance -80
Это так, что есть исторические записи на определенный момент времени.т.е. повторять транзакции с 48 часов назад.
В этом случае DB2 блокирует только учетную запись человека-1, а не всю таблицу (коллекцию), поскольку другие обновления учетной записи могут продолжаться одновременно
Обратите внимание, что в MongoDBоперация с одним документом является атомарной (даже без функции транзакции).Это связано с тем, что вы можете использовать внедренные документы и массивы для захвата отношений между данными в одной структуре документа вместо нормализации по нескольким документам и коллекциям, так как атомарность одного документа устраняет необходимость многодокументных транзакций для многихслучаи практического использования.См. Также Разработка модели данных MongoDB .