Я думаю, что вы пытаетесь решить проблему неправильно. То, что вы хотите, это максимальная защита целостности базы данных. Если два человека выполняют хранимую процедуру одновременно, согласованность базы данных может быть нарушена.
Для защиты от различных видов несоответствий базы данных стандарт SQL имеет четыре уровня изоляции транзакций:
- READ UNCOMMITTED, где в основном транзакции теряют свою ценность, другие транзакции видят грязные данные. Не используйте это!
- READ COMMITTED, где транзакции видят только зафиксированные данные, но могут быть несоответствия, когда две транзакции могут переступить через пальцы друг друга
- REPEATABLE READ, где решается один тип непоследовательности, неповторяемое чтение
- SERIALIZABLE, который гарантирует, что существует некоторый виртуальный порядок, в котором выполнение транзакций приведет к результатам, которые привели к их выполнению
Тем не менее, в стандарте SQL предусмотрен подход на основе блокировок для этих несоответствий базы данных, и по причинам производительности многие базы данных используют подход на основе моментальной копии, который в основном имеет эти уровни:
- READ COMMITTED - то же самое, что и в базах на основе блокировок
- ИЗОЛЯЦИЯ SNAPSHOT, где база данных видит моментальный снимок всех данных, и если она пытается обновить строку, которая была обновлена какой-либо другой транзакцией, она отменяется, однако существуют некоторые хорошо известные аномалии, которые могут иметь место
- SERIALIZABLE, то же самое, что и в базах данных на основе блокировок, но на этот раз реализовано по-другому, не путем взятия блокировок, а путем обеспечения отсутствия нарушений сериализации, и, если такое нарушение обнаружено, отмена транзакции
Отмена транзакций в этих базах данных, основанных на изоляции моментальных снимков, может показаться тревожной, но с другой стороны, каждая отдельная база данных будет отменять транзакцию из-за тупика, поэтому любое разумное приложение должно в любом случае иметь возможность повторить попытку транзакции.
Вам нужен уровень изоляции SERIALIZABLE : он гарантирует, что если транзакции, выполняемые независимо друг от друга, приводят к хорошему состоянию, любое параллельное выполнение транзакций также приводит к хорошему состоянию. К счастью, Майкл Кэхилл в своей докторской диссертации выяснил, как SERIALIZABLE уровень изоляции может поддерживаться изолированными базами данных моментальных снимков без особых усилий.
При использовании уровня изоляции SERIALIZABLE в изолированной базе данных моментальных снимков, если два человека пытаются запустить хранимую процедуру одновременно и наступают друг другу на ноги, одна из транзакций будет отменена.
Теперь, действительно ли SQL Server поддерживает уровень изоляции SERIALIZABLE (вместо маскировки изоляции моментального снимка за ключевым словом SERIALIZABLE )? Честно говоря, я не знаю: единственная база данных, которую я знаю, которая поддерживает это PostgreSQL.
Несмотря на то, что мне не удалось дать конкретный совет по SQL Server, я все равно публикую этот ответ, так как пользователи PostgreSQL и пользователи других баз данных, которые могут рассмотреть возможность перехода на PostgreSQL, могут извлечь пользу из моего ответа. Кроме того, пользователи баз данных, не относящихся к PostgreSQL, которые не могут переключиться на PostgreSQL, могут оказать давление на своих любимых поставщиков баз данных, чтобы они предложили подлинный СЕРИАЛИЗИРУЕМЫЙ уровень изоляции.