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

Posted

技术标签:

【中文标题】Sql Server - 即使事务回滚也会增加的计数器列【英文标题】:Sql Server - counter column that increments even with transactions rollback 【发布时间】:2018-08-08 07:27:42 【问题描述】:

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

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

是否有一种方法可以在所有事务都失败的情况下增加计数器,就像标识列一样?

谢谢, 大卫

附:我不能使用身份列,因为我不知道我必须管理多少个计数器。而且我也不能使用序列,我必须使用 SQL2008 数据库:-(

【问题讨论】:

为此创建一个带有标识列的表?而且我相信你不能做你想做的事(虽然不确定)。 序列也不会回滚。 请查看我更新的问题:不能使用标识列或序列。无论如何,感谢您的回答! 无论你在这里做什么,你都会遇到问题,因为你有潜在的并发问题。你过分强调增量价值。你说你还在用sql 2008,你什么时候升级。 2008 已经不支持了好几年了。是时候升级了!!! 序列对你来说是完美的,但在 MSSQL 2008 中不受支持。我唯一的想法是一个 CLR 函数,它访问一些外部存储(例如文件),防止全局互斥对象的并发访问。作为文件的替代方案,该 CLR 函数可以在内部连接到您自己的数据库并在单独的事务上下文中访问表。只是一个想法...... 【参考方案1】:

这是一个使用环回链接服务器连接的解决方案。这允许在当前事务上下文之外更新表:

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

【讨论】:

很聪明,但是master数据库是托管服务商管理的,我没有创建链接服务器的必要权限 嗯,在这种情况下,我看不到解决方案,抱歉。我希望这个答案对其他人有用......

以上是关于Sql Server - 即使事务回滚也会增加的计数器列的主要内容,如果未能解决你的问题,请参考以下文章

即使有事务回滚,SQL 标识(自动编号)也会增加

即使使用事务回滚,SQL标识(自动编号)也会增加

sql server存储过程回滚事务

为啥即使在 Spring 服务类的第二个方法中传播 = Propagation.REQUIRES_NEW 时事务也会回滚?

SQL Server事务执行一半出错是否自动回滚整个事务

SQL Server 2005 - 无法回滚嵌套事务