У меня есть хранимая процедура, которая запускает несколько команд. Я не хочу, чтобы эти команды были включены в транзакцию хранимой процедуры. Если 4-я команда терпит неудачу, я хочу, чтобы 1-я, 2-я и 3-я команды остались, а не откатывались.
Можно ли написать хранимую процедуру таким образом, чтобы она не выполнялась как одна большая транзакция?
Все транзакции не будут выполнены в одной транзакции. Взгляните на этот пример:
use TestDB;
go
ifexists(select1from sys.tables where object_id = object_id('dbo.TestTranTable1'))droptable dbo.TestTranTable1;createtable dbo.TestTranTable1
(
id int identity(1,1)notnull,
some_int int notnulldefault1);
go
insertinto dbo.TestTranTable1
defaultvalues;
go 4select*from dbo.TestTranTable1;ifexists(select1from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))begindropproc dbo.ChangeValues;end
go
createproc dbo.ChangeValues
asupdate dbo.TestTranTable1
set some_int =11where id =1;update dbo.TestTranTable1
set some_int =12where id =2;update dbo.TestTranTable1
set some_int =13where id =3;-- this will error out (arithmetic overflow)update dbo.TestTranTable1
set some_int =2147483648where id =4;
go
exec dbo.ChangeValues;select*from dbo.TestTranTable1;
Вот вывод:
Создавая сеанс расширенных событий для мониторинга этого sql_transactionсобытия, вы получите результат выполненияdbo.ChangeValues :
Как вы можете видеть на скриншоте выше, для каждого из четырех операторов существуют отдельные транзакции. Первые 3 коммита, а последний откатывается из-за ошибки.
Я думаю, что здесь может быть некоторая путаница относительно партии против транзакции .
Сделка является заявление или набор операторов , которые будут либо успеха или неудачи , как единое целое. Все операторы DDL находятся в самих транзакциях (то есть, если вы обновляете 100 строк, но строка 98 выдает ошибку, ни одна из строк не обновляется). Вы также можете заключить серию операторов в транзакцию, используя, BEGIN TRANSACTIONа затем либо COMMITили ROLLBACK.
Партия представляет собой последовательность операторов, которые выполняются вместе. Хранимая процедура является примером пакета. В хранимой процедуре, если один оператор завершается неудачно и происходит перехват ошибок (обычно TRY/CATCHблоки), последующие операторы не будут выполняться.
Я подозреваю, что ваша проблема в том, что пакет отменяется при возникновении ошибки, потому что либо сам хранимый процесс, либо внешняя область (например, приложение или хранимый процесс, который вызывает эту процедуру) содержит в себе перехват ошибок. Если дело обстоит именно так, решить это сложнее, поскольку вам нужно настроить способ обработки ошибок в любой области, в которой они находятся.
Я не нашел ни одной статьи, в которой говорилось бы: «Процедура магазина - это пример партии». Я считаю, что хранимая процедура очень похожа на пакетную, но это не пакетная процедура. Основное отличие состоит в том, что SP гарантированно будет скомпилирован заранее и готов к выполнению несколько раз в отличие от пакетов. Сходства: - Они оба выполняют каждую команду одновременно. - Если одна команда завершилась неудачно, то все предыдущие команды фиксируются (если она не выполнялась в транзакции) - если одна команда не удалась, все последующие команды не выполняются.
Аши
6
Все на сервере sql содержится в транзакции.
Когда вы явно указываете, begin transactionа end transactionзатем это называется явной транзакцией . Когда вы этого не сделаете, то это неявная транзакция .
Чтобы переключиться в какой режим вы используете, вы должны использовать
set implicit_transactions on
или
set implicit_transactions offselect@@OPTIONS &2
если выше возвращает 2, вы находитесь в неявном режиме транзакции. Если он возвращает 0, вы находитесь в автокоммите.
Транзакция - это ВСЕ или ничего для поддержания базы данных в согласованном состоянии. Запомните свойства ACID.
Вот как хранимые процедуры работают по умолчанию. Хранимая процедура не включается в транзакцию автоматически.
Если вы хотите, чтобы хранимая процедура остановилась при появлении первой ошибки, вы должны добавить туда логин TRY / CATCH для возврата в случае проблемы, например, с командой 2.
Я хочу квалифицировать, что для отдельных транзакций это поведение по умолчанию для хранимых процедур, потому что все операторы заключены в неявные транзакции; однако, никто не должен полагаться на неявные транзакции, чтобы контролировать судьбу своего кода. Гораздо эффективнее явно контролировать способ обработки транзакций в производственном коде.
отделите каждую из частей с помощью BEGIN TRAN и проверьте, была ли транзакция успешной. если это было зафиксировано, в противном случае выполните откат, поскольку все они выполняются с одного и того же уровня, вы сможете фиксировать каждый раздел отдельно, без необходимости откатывать все, если произойдет сбой.
Будет ли это создавать суб-транзакции в моей хранимой процедуре? В идеале я хотел бы избежать этого, если это возможно
Мэтью Стиплс
1
Если SP вызывается из транзакции, то ответом являются сохраненные транзакции. Если sp не вызывается с, тогда @mrdenny является правильным. Сервер Sql не поддерживает вложенные транзакции.
Чтобы быть понятным (и для ленивых, которые не хотят нажимать на ссылки), вы на самом деле не начинаете другую транзакцию. Ака заголовок на пост Павла: «Миф: Вложенные транзакции реальны». Это не настоящие сделки. COMMIT во вложенной транзакции ничего не делает, кроме декремента @@ TRANCOUNT. Это правда, что вы не получите ошибку, если вложите BEGIN TRAN / COMMIT, но это отличается от наличия реальных вложенных преобразований.
Все на сервере sql содержится в транзакции.
Когда вы явно указываете,
begin transaction
аend transaction
затем это называется явной транзакцией . Когда вы этого не сделаете, то это неявная транзакция .Чтобы переключиться в какой режим вы используете, вы должны использовать
или
если выше возвращает 2, вы находитесь в неявном режиме транзакции. Если он возвращает 0, вы находитесь в автокоммите.
Транзакция - это ВСЕ или ничего для поддержания базы данных в согласованном состоянии. Запомните свойства ACID.
- создать SP сейчас - обратите внимание, что первые 3 завершатся успешно, а 4-й завершится неудачей из-за усечения строки ...
Обратитесь к: Это плохая практика, чтобы всегда создавать транзакцию?
источник
Вот как хранимые процедуры работают по умолчанию. Хранимая процедура не включается в транзакцию автоматически.
Если вы хотите, чтобы хранимая процедура остановилась при появлении первой ошибки, вы должны добавить туда логин TRY / CATCH для возврата в случае проблемы, например, с командой 2.
источник
Вам понадобятся отдельные транзакции для каждой команды. Вы также можете сделать это с помощью сохраненных транзакций:
Смотрите
SAVE TRANSACTION (Transact-SQL)
в документации по продукту.Я хочу квалифицировать, что для отдельных транзакций это поведение по умолчанию для хранимых процедур, потому что все операторы заключены в неявные транзакции; однако, никто не должен полагаться на неявные транзакции, чтобы контролировать судьбу своего кода. Гораздо эффективнее явно контролировать способ обработки транзакций в производственном коде.
источник
отделите каждую из частей с помощью BEGIN TRAN и проверьте, была ли транзакция успешной. если это было зафиксировано, в противном случае выполните откат, поскольку все они выполняются с одного и того же уровня, вы сможете фиксировать каждый раздел отдельно, без необходимости откатывать все, если произойдет сбой.
Для получения дополнительной информации вы можете посмотреть по адресу: http://msdn.microsoft.com/en-us/library/ms188929.aspx
источник