我有SQL Server2005存储过程。有人正在事务中调用我的存储过程。在我的存储进程中,我记录了一些信息(插入到表中)。当更高级别的事务回滚时,它会删除我的insert。
有没有什么方法可以提交我的插入,并防止更高级别的回滚删除我的插入?
谢谢
发布于 2010-05-21 02:10:12
即使您启动了一个新事务,它也会嵌套在外部事务中。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'发布于 2010-05-21 02:14:46
在Oracle中,您可以使用自主事务来实现这一点,但是,SQL Server不支持它们。
可以声明一个表变量,然后从存储过程中返回它。
表变量在ROLLBACK中仍然存在,但是,应该修改上层代码以读取变量并永久存储其数据。
发布于 2010-05-21 02:24:27
根据权限,您可以使用xp_cmdshell调用OSQL,从而创建一个完全独立的连接。你也许可以用CLR做一些类似的事情,尽管我从来没有尝试过。然而,I强烈建议不要做这样的事情。
最好的办法是确定您的代码和调用代码的约定是什么-这两者之间支持哪种类型的约定。您可以制定一个规则,即您的代码永远不会在另一个事务中调用(可能不是一个好主意),或者您可以对调用代码在发生错误时负责什么提出要求。
https://stackoverflow.com/questions/2876568
复制相似问题