【问题标题】:Using TRY / CATCH to perform INSERT / UPDATE使用 TRY / CATCH 执行 INSERT / UPDATE
【发布时间】:2015-08-04 23:15:40
【问题描述】:

我在许多存储过程中都有这种模式

-- 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 where data = @data 中选择 null)开始 /* 在此处插入 */结束

但是,在这种情况下,我看不到解决方法。考虑以下替代方法。

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不好,但不会告诉我为什么

注意:我至少在一个机器上运行 SQL Server 2005,所以我不能使用MERGE

【问题讨论】:

  • 你刚刚杀死了我想到的第一个答案,即合并。 :)

标签: sql-server exception try-catch upsert


【解决方案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

【讨论】:

  • 根据 OP:注意:我在至少一个机器上运行 SQL Server 2005,所以我不能使用MERGE
  • @FelixPamittan 太糟糕了 :( 你可以做一个像这样的解决方法stackoverflow.com/questions/12621241/…
  • MERGE 也有一堆未解决的问题,所以犹豫要不要用。在这里阅读更多:mssqltips.com/sqlservertip/3074/…
  • @roryok 我编辑了我的答案,希望对您有所帮助。这似乎是丹的回答,但我认为,存在 cheking 是没有必要的
  • @Backs 是一个比 try/catch 更快的事务?
【解决方案2】:

显式事务是使用有条件的 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

【讨论】:

  • 这是否比 TRY / CATCH 方法执行得更好?
猜你喜欢
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 2015-08-19
  • 2012-05-27
  • 2021-12-19
  • 2015-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多