使用 TRY/CATCH 执行 INSERT/UPDATE
Using TRY / CATCH to perform INSERT / UPDATE
我在许多存储过程中都有这种模式
-- 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
You should never have exception "catching" in your normal logic flow. (Thus why it is called an "exception"..it should be exceptional (rare). Put a exists check around your INSERT. "if not exists (select null from Data where data = @data) begin /* insert here */ END
但是,在这种情况下我看不到解决方法。考虑以下替代方法。
INSERT INTO Table1 (data,count)
SELECT @data,1 WHERE NOT EXISTS
(SELECT 1 FROM Table1 WHERE data = @data)
如果我这样做,这意味着每个插入都是唯一的,但我不能 'catch' 更新条件。
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
尝试更新,如果失败 - 插入新的。
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
显式事务是为了解决并发问题而有条件地 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
。
我在许多存储过程中都有这种模式
-- 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
You should never have exception "catching" in your normal logic flow. (Thus why it is called an "exception"..it should be exceptional (rare). Put a exists check around your INSERT. "if not exists (select null from Data where data = @data) begin /* insert here */ END
但是,在这种情况下我看不到解决方法。考虑以下替代方法。
INSERT INTO Table1 (data,count)
SELECT @data,1 WHERE NOT EXISTS
(SELECT 1 FROM Table1 WHERE data = @data)
如果我这样做,这意味着每个插入都是唯一的,但我不能 'catch' 更新条件。
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
尝试更新,如果失败 - 插入新的。
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
显式事务是为了解决并发问题而有条件地 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
。