我有SQL Server 2005存储过程。有人在事务中调用我的存储过程。在我的存储过程中,我正在记录一些信息(插入表中)。当更高级别的事务回滚时,它会删除我的插入。
无论如何,我可以提交我的插入并阻止更高级别的回滚删除我的插入?
由于
答案 0 :(得分: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'
答案 1 :(得分:3)
在Oracle
中,您会使用自动交易,但SQL Server
不支持它们。
可以声明一个表变量并从存储过程中返回它。
表变量在ROLLBACK
之后存在,但是,应修改上层代码以读取变量并永久存储其数据。
答案 2 :(得分:2)
根据权限,您可以使用xp_cmdshell调用OSQL,从而创建完全独立的连接。您可能能够使用CLR执行类似的操作,但我从未尝试过。但是,我强烈建议不要这样做。
最好的办法是确定代码和调用代码的约定 - 两者之间支持哪种类型的契约。您可以规定,您的代码永远不会在另一个事务中被调用(可能不是一个好主意),或者您可以对发生错误时调用代码负责的内容提出要求。
答案 3 :(得分:1)
交易中的任何内容都将成为该交易的一部分。如果您不希望它成为该交易的一部分,那么请不要将其放入。