2010-05-20 6 views
2

У меня есть хранимая процедура SQL Server 2005. Кто-то вызывает мою хранимую процедуру в транзакции. В моем сохраненном proc я регистрирую некоторую информацию (вставляю в таблицу). Когда транзакция на более высоком уровне откатывается, она удаляет мою вставку.SQL Server Transactions Как я могу совершить транзакцию

В любом случае я могу зафиксировать свою вставку и предотвратить откат более высокого уровня от удаления моей вставки?

Благодаря

ответ

6

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

Это способ обойти это, это немного хитрость. Создайте связанный сервер с rpc out = true и remote proc transaction promotion = false. Связанный сервер может указывать на тот же сервер, на котором работает ваша процедура. Затем вы можете использовать execte (<query>) at <server>, чтобы выполнить что-то в новой транзакции.

if OBJECT_ID('logs') is not null drop table logs 
create table logs (id int primary key identity, msg varchar(max)) 
if OBJECT_ID('TestSp') is not null drop procedure TestSp 
go 
create procedure TestSp as 
execute ('insert into dbo.logs (msg) values (''test message'')') at LINKEDSERVER 
go 
begin transaction 
exec TestSp 
rollback transaction 
select top 10 * from logs 

Это закончится строкой в ​​таблице журналов, хотя транзакция была отброшена назад.

Вот пример кода для создания такого связанного сервера:

IF EXISTS (SELECT srv.name FROM sys.servers srv WHERE srv.server_id != 0 AND 
     srv.name = N'LINKEDSERVER') 
    EXEC master.dbo.sp_dropserver @server=N'LINKEDSERVER', 
     @droplogins='droplogins' 
EXEC master.dbo.sp_addlinkedserver @server = N'LINKEDSERVER', 
    @srvproduct=N'LOCALHOST', @provider=N'SQLNCLI', @datasrc=N'LOCALHOST', 
    @catalog=N'DatabaseName' 
EXEC master.dbo.sp_serveroption @server=N'LINKEDSERVER', @optname=N'rpc out', 
    @optvalue=N'true' 
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'LINKEDSERVER', 
    @useself=N'True', @locallogin=NULL,@rmtuser=NULL, @rmtpassword=NULL 
EXEC master.dbo.sp_serveroption @server=N'LINKEDSERVER', 
    @optname=N'remote proc transaction promotion', @optvalue=N'false' 
+0

Damm you SQL Server !!!! Мне нужна симпатичная функция. – codingguy3000

+0

@ codingguy3000: нашел трюк вокруг него, отредактировал ответ. Для этого требуются административные привилегии tho – Andomar

1

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

+0

Вызывающая хранимая процедура запускает транзакцию. Поэтому у меня нет возможности избежать участия в этой транзакции. – codingguy3000

+0

Можете ли вы перепроектировать, как это работает? Это звучит как плохой дизайн, в общем –

3

В Oracle вы использовали бы автономные транзакции для этого, однако SQL Server не поддерживает их.

Можно объявить переменную таблицы и вернуть ее из хранимой процедуры.

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

+0

Только то, что я собираюсь предложить – HLGEM

2

В зависимости от разрешений вы можете вызывать использование xp_cmdshell для OSQL, тем самым создавая совершенно отдельное соединение. Вы могли бы сделать что-то подобное с CLR, хотя я никогда не пробовал. Тем не менее, I сильно советуют делать что-то подобное.

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

Смежные вопросы