我需要为产品生命周期的每一年管理增量计数器(协议编号)。该值在每年内必须是唯一的,我需要一旦计数器递增,它就不能回滚。
如果我创建一个存储过程来创建其内部事务,当我的后端在其自己的事务中调用它并失败时,计数器将返回到先前的值。
是否存在一种方法来增加计数器,即使所有事务都失败了,比如标识列吗?
谢谢, 大卫
P.S。我不能使用标识列,因为我不知道我必须管理多少个计数器。我也不能使用序列,我必须使用SQL2008数据库: - (
答案 0 :(得分:0)
这是一个使用环回链接服务器连接的解决方案。这允许更新当前事务上下文之外的表:
use TEST; -- assume the database is named TEST
create table SeqNo (
SeqName nvarchar(10) not null primary key,
LastValue int default 0
);
insert into SeqNo (SeqName) values ('A'),('B');
create table Protocol (
id int not null primary key identity(1, 1),
SeqName nvarchar(10) not null,
SeqNo int not null,
SomeText nvarchar(100)
);
GO
EXEC master.dbo.sp_addlinkedserver @server = N'MyLoopback',
@srvproduct = N'',
@datasrc = @@SERVERNAME, -- use own server
@provider = N'SQLOLEDB',
@catalog=N'TEST';
GO
EXEC master.dbo.sp_serveroption @server=N'MyLoopback', @optname=N'remote proc transaction promotion', @optvalue=N'false';
EXEC master.dbo.sp_serveroption @server=N'MyLoopback', @optname=N'rpc', @optvalue=N'true';
EXEC master.dbo.sp_serveroption @server=N'MyLoopback', @optname=N'rpc out', @optvalue=N'true';
GO
/* We did the preparation work, now do a test... */
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;
declare @SeqName nvarchar(10);
set @SeqName = N'A';
declare @NewSeqNo int;
exec (N'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
declare @tmp table (NewValue int);
update SeqNo set LastValue = LastValue + 1 output inserted.LastValue into @tmp where SeqName = ?;
select top 1 ?=NewValue from @tmp;
COMMIT TRANSACTION;', @SeqName, @NewSeqNo output) at MyLoopback;
insert into Protocol (SeqName, SeqNo, SomeText) values (@SeqName, @NewSeqNo, N'Whatever you want');
ROLLBACK TRANSACTION; -- alternatively "COMMIT TRANSACTION" to have the row in Protocol persistent
select * from Protocol;
select * from SeqNo; -- became updated, even if rolled back (outer) transaction above