Как запустить запрос MongoDB с документом блокировки для последующего обновления? - PullRequest
0 голосов
/ 24 сентября 2018

Я пытаюсь найти точный ответ для этой ситуации в MongoDB, но не могу получить удовлетворительный ответ из любого источника.

Многие люди знакомы с этим примером в обучении баз данных, просто объясняя на случай, если кому-то нужно,Это пример в DB2.Баланс счета Лица-1 составляет $ 100,00.Человек-1 отправляется в кассу / банкомат, чтобы внести $ 20,00 на свой счет, обновление баланса имеет следующие шаги в системе.Для лучшего понимания я предоставляю время события.

  1. В 9: 00: 00: 000 AM прочитайте запись учетной записи Person-1, чтобы найти текущий баланс (запись блокировки DB2).Чтение в DB2 эквивалентно запросу mongoDB, DB2 имеет механизмы блокировки на уровне записи с чтением.
  2. В 9: 00: 00: 001 AM некоторые проверки аккаунта и добавление $ 20 к 100 = $ 120 говорят, что этот шаг занимает 2 секунды (обычно это не так, просто чтобы лучше понять механизм обновления))
  3. В 9: 00: 02: 001 обновите $ 120 для записи учетной записи Person-1 в DB2.

Друг Person-1 переводит $ 30 в Интернете в 9:00:00: 001 Если в это время система считывает учетную запись Person-1 для обновления, она добавляет от 30 до 100 долларов, и окончательный баланс станет 130 или 120 долларов, в зависимости от того, какое обновление баланса произойдет позже.Но баланс должен быть 150 долларов.

Чтобы избежать ошибки, DB2 устанавливает блокировку обновления для записи на шаге 1 выше, поэтому транзакция передачи по Интернету не может прочитать баланс для обновления, пока шаг 3 не будет выполнен (шаг 3 автоматически снимает блокировку).Кроме того, другие потоки могут читать записи в любое время, если они не читают для обновления.

Примечание: В этом случае DB2 блокирует только запись учетной записи человека-1, а не всю таблицу (коллекцию), поскольку другие обновления учетной записи могут продолжатьсяв то же время.

Может кто-нибудь объяснить, как это достигается в mongoDB?Я слышал, как некоторые люди говорили использовать флаг в документе и управлять им через прикладную программу, но это не совсем точно, это также может привести к потере баланса в вышеуказанном случае.

Спасибо, Нар

1 Ответ

0 голосов
/ 22 октября 2018

Может кто-нибудь объяснить, как это достигается в 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 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...