我在许多存储过程中都有这种模式
-- Table1
[id] [int] IDENTITY(1,1) NOT NULL
[data] [varchar](512) NULL
[count] INT NULL
-- 'data' is unique, with a unique index on 'data' in 'Table1'
BEGIN TRY
INSERT INTO Table1 (data, count) SELECT @data,1;
END TRY
BEGIN CATCH
UPDATE Table1 SET count = count + 1 WHERE data = @data;
END CATCH
我因为使用这种模式而被抨击before
你的正常逻辑流程中永远不应该有“捕获”异常。 (因此它被称为“异常”...它应该是例外的(罕见)。在INSERT周围进行存在检查。“如果不存在(从Data中选择null,其中data = @data)begin / * insert here * / END
但是,在这种情况下,我无法找到解决方法。考虑以下替代方法。
INSERT INTO Table1 (data,count)
SELECT @data,1 WHERE NOT EXISTS
(SELECT 1 FROM Table1 WHERE data = @data)
如果我这样做,则意味着每个插入都是唯一的,但我无法“捕获”更新条件。
DECLARE @id INT;
SET @id = (SELECT id FROM Table1 WHERE data = @data)
IF(@id IS NULL)
INSERT INTO Table1 (data, count) SELECT @data,1;
ELSE
UPDATE Table1 SET count = count + 1 WHERE data = @data;
如果我这样做,我在检查和插入之间有竞争条件,所以我可以插入重复项。
BEGIN TRANSACTION
DECLARE @id INT;
SET @id = (SELECT id FROM Table1 WHERE data = @data)
IF(@id IS NULL)
INSERT INTO Table1 (data, count) SELECT @data,1;
ELSE
UPDATE Table1 SET count = count + 1 WHERE data = @data;
END TRANSACTION
如果我将其包装在TRANSACTION
中,则会增加更多开销。我知道TRY/CATCH
也会带来开销但我认为 TRANSACTION
会增加更多 - 有人知道吗?
人们一直告诉我,在正常应用逻辑中使用TRY/CATCH
BAD ,但不会告诉我为什么
注意:我在至少一个盒子上运行SQL Server 2005,因此我无法使用MERGE
答案 0 :(得分:1)
尝试更新,如果失败,请插入新的。
BEGIN TRANSACTION
UPDATE t
SET
t.count = t.count + 1
FROM Table1 t
WHERE t.data = @data
IF (@@ROWCOUNT = 0)
BEGIN
INSERT INTO Table1
(data, count)
VALUES
(@data, 1)
END
COMMIT TRANSACTION
答案 1 :(得分:0)
显式事务是使用条件INSERT / UPDATE进行业务以解决并发问题的成本。下面的示例使用锁定提示来避免使用此代码的竞争条件。
BEGIN TRANSACTION;
INSERT INTO Table1
( data
, count
)
SELECT @data
, 1
WHERE NOT EXISTS ( SELECT 1
FROM Table1 WITH ( UPDLOCK, HOLDLOCK )
WHERE data = @data );
IF @@ROWCOUNT = 0
UPDATE Table1
SET count = count + 1
WHERE data = @data;
COMMIT;
如果更常见的路径是UPDATE
,请首先尝试使用条件INSERT
。