блокировка базы данных - PullRequest
       12

блокировка базы данных

4 голосов
/ 25 февраля 2010

У меня есть серверное приложение и база данных.Несколько экземпляров сервера могут работать одновременно, но все данные поступают из одной и той же базы данных (на некоторых серверах это postgresql, в других случаях ms sql server).

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

Процесс зависит от одной таблицы (назовем ее «ProcessTable»).Что я делаю, прежде чем какой-либо сервер запустит процесс продолжительностью в один час, я устанавливаю логический флаг в ProcessTable, который указывает, что эта запись «заблокирована» и обрабатывается (не все записи в этой таблице обрабатываются / блокируются, поэтому янеобходимо специально отметить каждую запись, которая необходима для процесса).Поэтому, когда следующий экземпляр сервера появляется, когда предыдущий экземпляр все еще обрабатывается, он видит логические флаги и выдает исключение.

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

Похоже, что мне нужна отдельная записьв моей таблице «Настройки», которая должна хранить логический флаг с именем «LockInProgress».Поэтому, прежде чем даже сервер сможет заблокировать необходимые записи в ProcessTable, он должен сначала убедиться, что у него есть полные права на блокировку, проверив столбец «LockInProgress» в таблице настроек.

Поэтому мой вопросКак я могу запретить двум серверам одновременно изменять этот столбец LockInProgress в таблице настроек ... или я поступаю неправильно?

Обратите внимание, что мне нужно поддерживать оба сервера postgresql и ms sql, поскольку некоторые серверы используют одну базу данных, а некоторые серверы используют другую.

Заранее спасибо ...

Ответы [ 3 ]

1 голос
/ 25 февраля 2010

Как насчет получения блокировки записи сначала, а затем обновить запись, чтобы показать "заблокирован".Это предотвратит успешную блокировку 2-го экземпляра и, следовательно, не удастся обновить запись.

Смысл в том, чтобы убедиться, что блокировка и обновление выполнены как один атомарный шаг.

0 голосов
/ 25 февраля 2010

Я думал об этом, и я думаю, что это самый простой способ делать вещи; Я просто выполняю такую ​​команду:

update settings set settingsValue = '333' where settingsKey = 'ProcessLock' and settingsValue = '0'

«333» будет уникальным значением, которое получает каждый процесс сервера (на основе даты / времени, имени сервера, + случайного значения и т. Д.).

Если никакой другой процесс не заблокировал таблицу, тогда settingsValue будет = 0, и этот оператор будет корректировать settingsValue.

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

Затем я немедленно фиксирую транзакцию.

Наконец, я запрашиваю таблицу для settingsValue, и если это правильное значение, тогда наша блокировка прошла успешно, и мы продолжаем, иначе выдается исключение и т. Д. Когда мы закончим с блокировкой, мы сбросим значение обратно до 0.

Поскольку я использую режим транзакции СЕРИАЛИЗАЦИЯ, я не вижу, чтобы это вызывало какие-либо проблемы ... пожалуйста, исправьте меня, если я ошибаюсь.

0 голосов
/ 25 февраля 2010

Создайте хранимую процедуру, которая раздает блокировку, и запускайте ее в «сериализуемой» изоляции. Это гарантирует, что один и только один процесс может получить доступ к ресурсу в любой момент времени.

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

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

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