Взаимосвязь между транзакциями в вложенных хранимых процедурах?
Я поместил транзакции во все мои «установленные» процедуры. Нет проблем. Все работает.
В этом случае мне нужна одна заданная процедура, чтобы назвать другую, к счастью, только один раз, или это потенциально усложнит ситуацию.
Так будет счастливая баня.
- Преобразование int в десятичное число в процедуре
- Оптимизация хранимой процедуры путем исключения избыточного оператора SELECT / запроса
- Сохраненная процедура и разрешения - достаточно ли ИСПОЛНИТЬ?
- Почему отчет SSRS истекает, когда хранимая процедура основана на результатах возврата в течение нескольких секунд?
- Добавление двух значений столбца в SQL Server для заполнения третьего столбца, можно ли это сделать без триггера / хранимой процедуры?
- Я в ProcA и начинаю транзакцию.
- Он вызывает ProcB и начинает транзакцию.
- ProcB успешно и совершает.
- ProcA успешно и совершает.
Однако, что произойдет, если ProcB не удастся, откатится и повторит ошибку. Это должно привести к откату ProcA, а также правильному?
Что делать, если ProcB преуспевает, комментирует, затем ProcA впоследствии терпит неудачу, а rollbackback … произойдет ли то, что произошло в ProcB? или он совершается?
Мне нужно, чтобы эти два человека работали вместе, либо оба успешно, либо потерпели неудачу, и оба были отброшены назад. Каков наилучший способ обеспечить это?
Я работаю с Microsoft SQL Server 2008 R2 (SP1)
Примечание. Если ProcB требует транзакции, потому что ее можно вызывать без обхода пакета ProcA. И технически, ProcA не всегда будет вызывать ProcB (зависит от ввода).
- библиотеки безопасности для SQL Server
- Получение инструкции sql, которая отображает представление, sp или функцию, MSSQL
- Округление UP в SQL Server?
- Объект SQL SSRS был отключен или не существует на сервере
- Хранимая процедура SQL Server - как отсортировать записи с древовидным форматом?
- Метод Sane / fast для передачи списков переменных параметров в хранимую процедуру SqlServer2008
- Открыть симметричный ключ с паролем в хранимой процедуре
- Как проверить, существует ли представление в базе данных?
Вот простая демонстрация, показывающая, что происходит с вложенными трансациями:
CREATE TABLE TranTest (Field1 INTEGER) BEGIN TRANSACTION SELECT @@TRANCOUNT -- 1 open transaction INSERT TranTest VALUES (1) BEGIN TRANSACTION SELECT @@TRANCOUNT -- 2 open transactions INSERT TranTest VALUES (2) ROLLBACK TRANSACTION -- this rolls back ALL transaction SELECT @@TRANCOUNT -- 0 open transactions (you may have expected 1?) SELECT * FROM TranTest -- No rows
Вместо этого ROLLBACK выше, если вы выполнили COMMIT TRANSACTION, это фактически ничего не делает, а затем уменьшает @@ TRANCOUNT. Таким образом, вам тогда понадобится либо COMMIT внешняя транзакция (которая будет COMMIT обе строки в таблице), либо сделать ROLLBACK, из-за чего строки не будут привязаны к таблице.
Вот ссылка MSDN на вложенные транзакции: http://msdn.microsoft.com/en-us/library/ms189336.aspx
Просто используйте XACT_ABORT ON, и вы все настроены. Запустите следующий скрипт и убедитесь сами:
CREATE DATABASE ak_test; GO USE ak_test; GO CREATE TABLE dbo.a(i INT CONSTRAINT a_CannotInsertNegative CHECK(i>=0)); GO CREATE TABLE dbo.b(i INT CONSTRAINT b_CannotInsertNegative CHECK(i>=0)); GO CREATE PROCEDURE dbo.innerProc @i INT AS SET XACT_ABORT ON ; BEGIN TRAN INSERT b(i)VALUES(@i); COMMIT; GO CREATE PROCEDURE dbo.outerProc @i1 INT, @i2 INT, @i3 INT AS SET XACT_ABORT ON ; BEGIN TRAN INSERT a(i)VALUES(@i1); EXEC innerProc @[email protected]; INSERT a(i)VALUES(@i3); COMMIT; GO -- succeeds EXEC dbo.outerProc 1, 2, 3; SELECT * FROM dbo.a; SELECT * FROM dbo.b; GO -- inner proc fails EXEC dbo.outerProc 2, -3, 4; GO SELECT * FROM dbo.a; SELECT * FROM dbo.b; GO -- second insert in outer proc fails EXEC dbo.outerProc 3, 4, -5; GO SELECT * FROM dbo.a; SELECT * FROM dbo.b;
Я параноик по поводу транзакций (эта транзакция осталась открытой на Production, когда никто не заметил в течение получаса …), поэтому я бы деформировал потенциально внутреннюю транзакцию следующим образом:
CREATE PROCEDURE etcetc ... DECLARE @IsTransaction bit = 0 IF @@trancount > 0 BEGIN BEGIN TRANSACTION SET @IsTransaction = 1 END ... IF @IsTransaction = 1 BEGIN COMMIT -- or ROLLBACk, as necessary END
Вся обработка транзакций (и обработка ошибок, возникающих в транзакции) должна обрабатываться на любом уровне запуска транзакции.
(И кто-нибудь еще заметил, что BOL фактически не говорит, что происходит, когда вы выдаете ROLLBACK для именованной транзакции, которая не является самой внешней транзакцией? Они описывают каждую другую перестановку …)