-1

假设我有两列 CategoryId 和 SubcategoryId。对于每个 CategoryId,SubcategoryId 从 1 开始。插入新的子类别时,我需要为给定的 CategoryId 计算 MAX(SubcategoryId)+1。

以下是正确的吗?

BEGIN TRANSACTION
DECLARE @NextId bigint;
SELECT @NextId = ISNULL(MAX(SubcategoryId),0) + 1 
FROM Subcategory WITH (UPDLOCK, HOLDLOCK) 
WHERE CategoryId = @CategoryId;
INSERT INTO Subcategory
(
    CategoryId, 
    SubcategoryId
) 
VALUES
(
    @CategoryId, 
    @NextId
 );
COMMIT

WITH(UPDLOCK, HOLDLOCK) 是否也防止同时插入具有相同 CategoryId 的新行,还是仅锁定在 SELECT 时匹配的现有行?如果是后者,我应该将其更改为 TABLOCK 吗?是否也需要某种排他锁?

4

1 回答 1

1

一般来说,除非您有非常特殊的要求,否则不建议搞乱锁定级别。据我了解,有一种方法可以让您的并发问题由 SQL 服务器引擎处理,而无需锁定提示。

所以你的表定义是:

CREATE TABLE Subcategory
(
   CategoryId bigint, 
   SubcategoryId bigint
 )

如果将表定义更改为:

CREATE TABLE Subcategory
(
   CategoryId bigint NOT NULL, 
   SubcategoryId bigint IDENTITY(1,1) NOT NULL
 ) ON [PRIMARY];
 ALTER TABLE Subcategory
 ADD CONSTRAINT pk_Subcategory PRIMARY KEY (CategoryId,SubcategoryId  )

SubcategoryID 将成为自动编号。这个数字将在每次插入时递增。因此,您不需要在插入过程中指定子类别 ID,这将允许 SQL Server 处理并发性。最好让SQL处理表的锁定和并发处理。

如果您将表结构更改为我建议的结构,您的查询也会变得更简单。

BEGIN TRAN
INSERT INTO Subcategory
(
    CategoryId, 

) 
VALUES
(
    @CategoryId, 

 );
 COMMIT TRAN

这可能是您的解决方案。抱歉,我的语法可能是错误的,因为我已经好几个月没有接触过 SQL 服务器了。

于 2012-12-07T09:11:48.767 回答