SQL Server自定义标识列

时间:2015-04-29 07:46:29

标签: sql-server concurrency identity

我想生成与产品类型相关的自定义标识列。 此查询可以保证身份的顺序并解决并发问题。 这是一个示例查询:

BEGIN TRAN

INSERT INTO TBLKEY
VALUES((SELECT 'A-' + CAST(MAX(CAST(ID AS INT)) + 1 AS NVARCHAR) FROM TBLKEY),'EHSAN')

COMMIT

2 个答案:

答案 0 :(得分:0)

这样做是件坏事,因为无法保证同时运行的两个查询不会使MAX(ID)成为相同的值。

如果您使用标准标识列,则还可以使用计算列来使用该列,或者在返回数据时返回密钥。

答案 1 :(得分:0)

试试这个:

BEGIN TRAN

INSERT INTO TBLKEY
VALUES((SELECT MAX(ID) + 1 AS NVARCHAR) FROM TBLKEY WITH (UPDLOCK)),'EHSAN')

COMMIT

选择最大ID时,您会在该行上获得U锁定。 U锁与U锁不兼容,U锁将尝试使用同时运行的同一查询获取另一个会话。在给定时间只执行一个查询。 ids将按顺序连续,没有任何间隙。

更好的解决方案是创建一个专用于存储当前或下一个id的额外表,并使用它而不是最大值。

您可以通过执行以下操作来了解其中的区别:

准备一张桌子

CREATE TABLE T(id int not null PRIMARY KEY CLUSTERED)
INSERT INTO T VALUES(1)

然后在两个不同的会话中一个接一个地运行以下查询,间隔不到10秒

BEGIN TRAN
DECLARE @idv int
SELECT @idv = max (id) FROM T
WAITFOR DELAY '0:0:10'
INSERT INTO T VALUES(@idv+1)
COMMIT

等待一段时间,直到两个查询完成。观察到其中一个成功而另一个失败。

现在对以下查询执行相同的操作

BEGIN TRAN
DECLARE @idv int
SELECT @idv = max (id) FROM T WITH (UPDLOCK)
WAITFOR DELAY '0:0:5'
INSERT INTO T VALUES(@idv+1)
COMMIT

查看T

的内容

使用DROP TABLE T

清理T表