У меня есть хранимая процедура, которая в основном выбирает значения из одной таблицы и вставляет их в другую, что-то вроде архивирования. Я хочу, чтобы несколько человек не делали это одновременно.
Пока эта процедура запущена, я не хочу, чтобы кто-либо другой мог ее запустить, однако я не хочу, чтобы сериализация выполнялась другим человеком после того, как я закончу с ним.
Я хочу, чтобы другой человек, пытающийся запустить его, получил ошибку, пока я выполняю процедуру.
Я пытался использовать sp_getapplock, однако мне не удается полностью остановить человека от выполнения процедуры.
Я также попытался найти процедуру с sys.dm_exec_requests и заблокировать процедуру, хотя это работает, я думаю, что это не оптимально, потому что на некоторых серверах у меня нет прав на запуск sys.dm_exec_sql_text (sql_handle).
Какой лучший способ для меня это сделать?
источник
Ответы:
Чтобы добавить ответ @ Tibor-Karaszi, установка таймаута блокировки на самом деле не приводит к ошибке (я отправил PR против документов). sp_getapplock просто возвращает -1, поэтому вы должны проверить возвращаемое значение. Ну вот так:
источник
Используйте sp_getapplock в начале процедуры и установите для тайм-аута блокировки очень низкое значение. Таким образом, вы получаете ошибку, когда вы заблокированы.
источник
Другой вариант - создать таблицу для контроля доступа к процедуре. В приведенном ниже примере показана возможная таблица, а также процедура, которая может ее использовать.
источник
IsLocked
состояние до 0 в этом случае? Мне также любопытно ваше использованиеCOALESCE
здесь. Может@@ROWCOUNT
быть нуль после утверждения нравитсяUPDATE
? И, наконец, просто незначительный прыщ, зачем ставить точку с запятой передTHROW
утверждением в этом конкретном случае?Я думаю, что вы пытаетесь решить проблему неправильно. То, что вы хотите, это максимальная защита целостности базы данных. Если два человека выполняют хранимую процедуру одновременно, согласованность базы данных может быть нарушена.
Для защиты от различных видов несоответствий базы данных стандарт SQL имеет четыре уровня изоляции транзакций:
Тем не менее, в стандарте SQL предусмотрен подход на основе блокировок для этих несоответствий базы данных, и по причинам производительности многие базы данных используют подход на основе моментальной копии, который в основном имеет эти уровни:
Отмена транзакций в этих базах данных, основанных на изоляции моментальных снимков, может показаться тревожной, но с другой стороны, каждая отдельная база данных будет отменять транзакцию из-за тупика, поэтому любое разумное приложение должно в любом случае иметь возможность повторить попытку транзакции.
Вам нужен уровень изоляции SERIALIZABLE : он гарантирует, что если транзакции, выполняемые независимо друг от друга, приводят к хорошему состоянию, любое параллельное выполнение транзакций также приводит к хорошему состоянию. К счастью, Майкл Кэхилл в своей докторской диссертации выяснил, как SERIALIZABLE уровень изоляции может поддерживаться изолированными базами данных моментальных снимков без особых усилий.
При использовании уровня изоляции SERIALIZABLE в изолированной базе данных моментальных снимков, если два человека пытаются запустить хранимую процедуру одновременно и наступают друг другу на ноги, одна из транзакций будет отменена.
Теперь, действительно ли SQL Server поддерживает уровень изоляции SERIALIZABLE (вместо маскировки изоляции моментального снимка за ключевым словом SERIALIZABLE )? Честно говоря, я не знаю: единственная база данных, которую я знаю, которая поддерживает это PostgreSQL.
Несмотря на то, что мне не удалось дать конкретный совет по SQL Server, я все равно публикую этот ответ, так как пользователи PostgreSQL и пользователи других баз данных, которые могут рассмотреть возможность перехода на PostgreSQL, могут извлечь пользу из моего ответа. Кроме того, пользователи баз данных, не относящихся к PostgreSQL, которые не могут переключиться на PostgreSQL, могут оказать давление на своих любимых поставщиков баз данных, чтобы они предложили подлинный СЕРИАЛИЗИРУЕМЫЙ уровень изоляции.
источник
Я понимаю, что «настоящая» проблема может быть более сложной.
Если это не так: если вы выполняете архивирование с помощью триггеров вставки и / или обновления, вы можете избежать проблемы, которую пытаетесь решить.
Надеюсь, это поможет,
Крис С.
источник
the 'real' problem may be more complex
. В случае, если это не так, триггеры являются хорошим решением. Плюс, вероятно, будет проще протестировать и поддерживать, потому что это особенность базы данных, а не пользовательское решение.