Sql Server - 计数器列,即使事务回滚也会递增

时间:2018-02-28 12:05:19

标签: sql-server transactions identity-column

我需要为产品生命周期的每一年管理增量计数器(协议编号)。该值在每年内必须是唯一的,我需要一旦计数器递增,它就不能回滚。

如果我创建一个存储过程来创建其内部事务,当我的后端在其自己的事务中调用它并失败时,计数器将返回到先前的值。

是否存在一种方法来增加计数器,即使所有事务都失败了,比如标识列吗?

谢谢, 大卫

P.S。我不能使用标识列,因为我不知道我必须管理多少个计数器。我也不能使用序列,我必须使用SQL2008数据库: - (

1 个答案:

答案 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