SQL Server Как всегда откатывать всю транзакцию

У меня несколько необычная потребность в обработке транзакций.

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

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

высокий уровень выглядит так

start transaction
initialize test
run test with user code
   may or may not contain:
      - start tran
      - start tran savename
      - commit tran
      - commit tran savename
      - rollback tran
      - rollback tran savename
output testresults
rollback transaction

Есть ли способ убедиться, что я всегда могу вернуться к исходному состоянию? Я должен принять во внимание, что пользователи могут вызывать хранимые процедуры/триггеры, которые могут быть вложенными, и все они могут содержать операторы транзакций. Со всеми моими решениями в тот момент, когда пользователь использует откат транзакций в своем тестовом коде, они избегают транзакции, и не все будет очищено.

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

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

rollback tran всегда откатывайте всю транзакцию. Если вашим пользователям разрешено вызывать это, им разрешено откатывать вашу транзакцию. Вы ничего не можете с этим поделать. Код, который делает это, является PITA для использования. Их код нужно писать так, чтобы не откатывать не начатые им транзакции.

GSerg 28.06.2019 11:37

Возможная альтернатива — использовать снимки базы данных для возврата базы данных в любое желаемое состояние независимо от того, что произошло в транзакциях. Начиная с SQL Server 2016 SP1, они доступны во всех выпусках; до этого они были доступны только в Enterprise и Developer.

Jeroen Mostert 28.06.2019 13:49

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

H3llskrieg 28.06.2019 14:27

Это будет сильно зависеть от того, что делают ваши транзакции; вам нужно проверить. Прошло некоторое время с тех пор, как я действительно тестировал эту настройку. Возврат к моментальному снимку, безусловно, быстрее, чем резервное копирование/восстановление (даже инкрементное), но не быстрее, чем очень тривиальные операторы SQL. Основное преимущество заключается в том, что вы не зависите от конкретных действий кода. Лично я ценю надежность тестов гораздо выше, чем скорость их выполнения. Вы всегда можете масштабировать запущенные тесты, бросив на них больше ресурсов (в данном случае несколько БД и параллелизм), но с надежностью не так повезло.

Jeroen Mostert 28.06.2019 14:35

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

H3llskrieg 28.06.2019 15:28
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
5
492
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Я не думаю, что это возможно без каких-либо сообщений/правил для пользовательского кода. Несмотря на то, что вы делаете, если пользовательский код запустит столько COMMIT, сколько есть @@TRANCOUNT в это время, транзакция будет зафиксирована, и вы ничего не сможете с этим поделать.

Один из способов сделать это — проверить/принудить пользовательский код вместо использования COMMIT изменить его на if @@TRANCOUNT>=2 COMMIT. Это гарантирует, что ИСТИННАЯ фиксация данных может быть выполнена только ВАШЕЙ командой COMMIT. Конечно, бывает, что никогда особо не хочется коммита, так что просто rollback и все кончено.

Вы упоминаете:

What I want is that if a user calls rollback only their part of the transaction is rolled back

Обратите внимание, что вложенные транзакции — это своего рода миф. См. эта отличная статья. Короче говоря: «вложенные» BEGIN TRANSACTION и COMMIT на самом деле ничего не делают, кроме изменения значения системной переменной @@TRANCOUNT, чтобы можно было организовать некоторую организацию с помощью процедур.

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

H3llskrieg 28.06.2019 11:36

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

H3llskrieg 28.06.2019 11:37

Принуждение пользователей к использованию блока try/transaction/catch — это решение, которое может занять больше времени, но в целом является хорошей практикой. Одним из возможных вариантов может быть Erland Sommerskog: sommarskog.se/error_handling/Part1.html#jumpgeneralpattern . Имейте в виду, однако, что принудительное использование блока должно означать запрет на использование commit внутри раздела функционального кода, поэтому, похоже, вы не можете избежать этой части.

George Menoutis 28.06.2019 11:40

Я не думаю, что можно откатить часть транзакции и сохранить другую транзакцию нетронутой. В тот момент, когда мы откатываем транзакцию, откатывается вся транзакция.

Ответ принят как подходящий

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

Я также решил провалить тест, когда начальный @@TRANCOUNT и конечный @@TRANCOUNT не совпадают, чтобы ни один тест не мог пройти, когда с транзакциями пользователей что-то не так.

Однако текущая система по-прежнему будет бороться с пользователем, выполняющим COMMIT TRAN. Это проблема в другой раз.

Я считаю, что на самом деле необходимо написать тестовые примеры для T-SQL. Если это так, то я чувствую, что вам не нужно изобретать велосипед и начинать использовать среду тестирования с открытым исходным кодом T-SQLT https://tsqlt.org/.

Я знаю о tsqlt, и я черпал из него вдохновение, проблема в том, что он не поддерживает проверку шпионажа, надлежащее покрытие кода или тестирование мутаций.

H3llskrieg 29.06.2019 15:58

Другие вопросы по теме