为几句话锁定数据库 table

Lock database table for just a couple of sentences

假设 SQLServer 中的 table 具有以下结构:

TABLE t (Id INT PRIMARY KEY)

然后我有一个不断被调用的存储过程,它可以在此 table 中插入数据以及其他类型的东西:

BEGIN TRAN

DECLARE @Id INT = SELECT MAX(Id) + 1 FROM t

INSERT t VALUES (@Id)

...
-- Stuff that gets a long time to get completed
...

COMMIT

这种方法的问题是有时我会遇到主键冲突,因为 2 个或更多过程调用获取并尝试在 table 上插入相同的 ID。

我已经能够解决这个问题,在 SELECT 句子中添加一个制表块:

DECLARE @Id INT = SELECT MAX(Id) + 1 FROM t WITH (TABLOCK)

现在的问题是对过程的连续调用必须等待当前正在执行的事务完成才能开始工作,只允许一个过程同时运行。

在select and insert 语句的执行过程中,有没有什么技巧或技巧可以获取锁?

谢谢。

TABLOCK 是个糟糕的主意,因为您要序列化所有调用(没有并发)。 请注意,对于 SP,您将保留通过 运行 授予的所有锁,直到 SP 完成。 所以除了你真正需要的地方,你想尽量减少锁。

除非有特殊情况,否则请使用内部生成的 ID:

CREATE TABLE t (Id INT IDENTITY PRIMARY KEY)

提高了性能、并发性等,因为您不依赖于外部表来管理 ID。

如果您有现有数据,您可以使用 DBCC

(重新)设置起始值
DBCC CHECKIDENT ('t', RESEED, 100)

如果您需要注入具有预分配值的行,请使用:

SET IDENTITY_INSERT t ON

(然后再次关闭,根据需要重置种子)。

[考虑您是否希望此值成为主键,或者只是唯一的。 在许多情况下,您需要将表 PK 引用为 FK,然后您希望它作为 PK 以简化连接,但具有业务可读值(例如,Accounting Code 或 OrderNo+OrderLine 是完全有效的):这只是建模]