Невозможно заблокировать документ mongodb. Что если мне нужно?

Я знаю, что не могу заблокировать один документ mongodb, фактически, также нет способа заблокировать коллекцию.

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

У меня есть коллекция, которая содержит объект типа А. У меня есть некоторый код, который извлекает документ типа А, добавить элемент в массив, который является свойством документа (a.arr.add(new Thing()) и затем сохраните документ обратно в mongodb. Этот код параллелен, несколько потоков в моих приложениях могут выполнять эти операции, и на данный момент нет способа помешать потокам выполнять эти операции параллельно в одном и том же документе. Это плохо, потому что один из потоков может перезаписать работы другого.

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

Теперь, когда я думаю об этом, может быть, это ограничение шаблона репозитория, а не ограничение mongodb, которое доставляет мне неприятности. В любом случае, как я могу сделать этот код "потокобезопасным"? Я думаю, что есть хорошо известное решение этой проблемы, но, будучи новичком в mongodb и в шаблоне репозитория, я не сразу его вижу.

Спасибо

Ответы на вопрос(12)

$ толчок Оператор должен быть достаточно безопасным, чтобы не допустить перезаписи потоков изменениями друг друга.

this& Quot;

"Тогда не делай"do ! Что & Quot;

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

Итак, место для поиска - ваш алгоритм. Вы можете устранить это? Не могли бы вы, например, справиться с этим с помощью какого-либо разрешения конфликта, например & quot; получить запись в локальном & apos; Обновить; сохранить запись & quot; так, чтобы после магазина новая запись была получена на этот ключ?

 02 апр. 2018 г., 13:07
Отличный комментарий. Не делайте этого, даже если это работа, которую вы ДОЛЖНЫ делать, просто потому, что какой-то инструмент недостаточно хорош.
 03 апр. 2018 г., 01:03
Я сделал. Как трудно может быть попытка не дать какую-то общую мудрость в начале ответа, просто чтобы показать, что автор темы не достаточно умен?
 16 дек. 2018 г., 07:50
MongoDB finally supports Transactions : Dstackoverflow.com/a/53800048/2757916
 02 апр. 2018 г., 20:00
@AnatolyAlekseev, если MongoDB этого не сделает, он этого не сделает. И посмотрите на остальную часть того, что я сказал: «Итак, вам стоит взглянуть на ваш алгоритм. Вы можете устранить это? & Quot; Прочитайте весь ответ и не будьте проклятым дураком.
 Mathieu Pagé18 июн. 2012 г., 04:28
Я, Чарли, спасибо за ответ. Я не понимаю решение конфликта, которое вы предлагаете. Я согласен, что мне нужно изменить свой алгоритм, и я могу представить какое-то решение, но я чувствую, что должно быть какое-то согласованное решение этой проблемы. Мне кажется, что это классическая проблема, с которой сталкиваются многие люди, использующие mongodb (или, возможно, любую базу данных). Если бы это было обновление памяти, я бы знал, как использовать мьютекс для «блокировки». переменная, которую я хочу обновить, чтобы обновлять ее мог только один поток. Наверное, мой вопрос: как другие программисты обычно справляются с этой ситуацией?

Update: тве механизма по умолчанию MongoDB использует блокировку по умолчанию на уровне документа. Она была введена в версии 3.0, но по умолчанию установлена в версии 3.2.2. Поэтому MongoDB теперь имеет блокировку на уровне документа.

1 серверов, тогда вам потребуется распределительная блокировка.

Я предпочитаю использоватьHazelcast.

При сохранении вы можете получить блокировку Hazelcast по идентификатору объекта, получить и обновить данные, а затем снять блокировку.

В качестве примера: https://github.com/azee/template-api/blob/master/template-rest/src/main/java/com/mycompany/template/scheduler/SchedulerJob.java

Просто используйтеlock.lock() вместоlock.tryLock()

Здесь вы можете увидеть, как настроить Hazelcast в своем весеннем контексте:

https://github.com/azee/template-api/blob/master/template-rest/src/main/resources/webContext.xml

операции для наборов реплик. Поддержка сегментированных кластеров появится в MongoDB 4.2. При использовании транзакций фиксация обновлений БД будет прервана в случае конфликтующей записи, что решит вашу проблему.

Транзакции намного дороже с точки зрения производительности, поэтому не используйте Транзакции как оправдание плохого дизайна схемы NoSQL!

потому что я нашел решение, когда проводил исследования в Интернете.

Я думаю, что мне нужно сделать, это использоватьОптимистичный Контроль Конкуренции.

Он состоит в добавлении временной метки, хэша или другого уникального идентификатора (я использовал UUID) к каждому документу. Уникальный идентификатор должен быть изменен каждый раз, когда изменяется документ. перед обновлением документа я сделаю что-то вроде этого (в псевдокоде):

var oldUUID = doc.uuid;
doc.uuid = new UUID();
BeginTransaction();
if (GetDocUUIDFromDatabase(doc.id) == oldUUID)
{
   SaveToDatabase(doc);
   Commit();
}
else
{
   // Document was modified in the DB since we read it. We can't save our changes.
   RollBack();
   throw new ConcurencyException();
}
 19 июн. 2012 г., 05:05
Да, это один из способов разрешения конфликтов.
 30 окт. 2012 г., 08:48
Вы можете сделать это, но используя атомарные операторы, некоторые из других описанных ответов, вероятно, то, что вы хотите (и атомарно, как вы хотите). Вот документы:mongodb.org/display/DOCS/Atomic+Operations
Решение Вопроса

работая над обновлениями mongodb. В отличие от того времени, когда был задан этот вопрос, теперь mongodb поддерживает блокировку на уровне документа из коробки.

От:http://docs.mongodb.org/manual/faq/concurrency/

& quot; Насколько гранулированы блокировки в MongoDB?

Изменено в версии 3.0.

Начиная с версии 3.0, MongoDB поставляется с механизмом хранения WiredTiger, который использует оптимистичный контроль параллелизма для большинства операций чтения и записи. WiredTiger использует только намеренные блокировки на глобальном уровне, уровне базы данных и уровне сбора. Когда механизм хранения обнаруживает конфликты между двумя операциями, одна из них вызывает конфликт записи, в результате чего MongoDB прозрачно повторяет эту операцию. & Quot;

 03 июн. 2016 г., 18:13
Что делать, если я хочу заблокировать при создании объекта документа?

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

Так, скажем, вы добавляете атрибут статуса, а когда вы извлекаете документ, меняете статус с «IDLE». на "ОБРАБОТКУ". Затем вы обновляете документ и сохраняете его обратно в коллекцию, обновляя статус до «IDLE». снова.

Пример кода:

var doc = db.runCommand({
              "findAndModify" : "COLLECTION_NAME",
              "query" : {"_id": "ID_DOCUMENT", "status" : "IDLE"},
              "update" : {"$set" : {"status" : "RUNNING"} }
}).value

Измените COLLECTION_NAME и ID_DOCUMENT на правильное значение. По умолчанию findAndModify () возвращает старое значение, что означает, что значение состояния все еще будет IDLE на стороне клиента. Поэтому, когда вы закончите с обновлением, просто сохраните / обновите все снова.

Единственное, что вам нужно знать, это то, что вы можете изменять только один документ за раз.

Надеюсь, поможет.

 03 июн. 2016 г., 18:13
Что делать, если я хочу заблокировать при создании объекта документа?
 02 апр. 2018 г., 13:06
Обидно, что они не расширили findAndModify () для работы с несколькими документами.
 05 июн. 2016 г., 01:31
@slezica прав, и вы можете найти решение? Как другой клиент узнает об освобождении заблокированного документа?
 23 нояб. 2013 г., 11:28
Вы можете использовать простой update () для той же цели, что является официальным решением, предлагаемым на сайте MongoDB:docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations  Основное осложнение этого решения заключается в том, что вы должны написать код для случая, когда обновление не удалось. То есть Повторите обновление. В зависимости от вашего кода вам могут потребоваться дополнительные сложности, чтобы избежать побочных эффектов при повторных попытках и т. Д.
 01 дек. 2014 г., 22:00
Как другой клиент ожидает снятия блокировки? то есть как вы можете получать уведомления, когдаstatus изменения?

я пытаюсь ответить на этот вопрос: мне интересно, справится ли это хранилище WiredTiger с проблемой, которую я указал здесь: Предельные вставки в mongodb

на месте обновления

Например:

http://www.mongodb.org/display/DOCS/Updating#comment-41821928

db.users.update( { level: "Sourcerer" }, { '$push' : { 'inventory' : 'magic wand'} }, false, true );

который будет толкать «волшебную палочку» во все "Sourcerer" массив инвентаря пользователя. Обновление для каждого документа / пользователя является атомарным.

когда вы хотите сделать что-то поточно-ориентированное, - это использовать блокировки (мьютексы). Это также называетсяpessimistic locking в отличие отoptimistic locking описаноВот.

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

MongoDB не предоставляет механизм блокировки. Но это может быть легко реализовано на уровне приложения (т. Е. В вашем коде):

Acquire lock Read document Modify document Write document Release lock

Степень детализации блокировки может быть различной: глобальная, специфичная для коллекции, специфичная для записи / документа. Чем конкретнее блокировка, тем меньше ее производительность.

 01 дек. 2014 г., 21:59
Как ты ждешь на замке?
 22 июн. 2015 г., 07:23
Это не работает в приложении с несколькими экземплярами.
 02 дек. 2014 г., 22:50
Действие получения блокировки обычно ожидает блокировки, если она удерживается другим потоком.
 Mathieu Pagé30 окт. 2012 г., 13:43
Проблема с атомарными операторами состоит в том, что они действительно не помогают мне, так как я использовал шаблоны репозитория, поэтому у меня были только операции CRUD.

Ваш ответ на вопрос