Даже если вы начинаете новую транзакцию, то он будет вложен в пределах внешней транзакции. 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'
Damm you SQL Server !!!! Мне нужна симпатичная функция. – codingguy3000
@ codingguy3000: нашел трюк вокруг него, отредактировал ответ. Для этого требуются административные привилегии tho – Andomar