【问题标题】:Stored procedure best practice? Should they check if foreign keys exist before inserting?存储过程最佳实践?他们应该在插入之前检查外键是否存在吗?
【发布时间】:2016-04-13 09:10:53
【问题描述】:

在构建插入简单链接表的存储过程时,它应该检查 FK 是否存在并优雅地返回错误,还是让 SQL 抛出异常?

  • 最佳做法是什么?
  • 什么是最有效的?

以防有人不明白我的问题:

  • Table A
  • Table B
  • Table AB

我应该这样做:

IF EXISTS(SELECT 1 FROM A WHERE Id = @A) AND EXISTS(SELECT 1 FROM B WHERE Id = @B)
BEGIN
      INSERT AB (AId,BId) VALUES (@A,  @B)
END
ELSE
   --handle gracefully, return error code or something

INSERT AB (AId,BId) VALUES (@A, @B)

让 SQL 抛出异常

谢谢

【问题讨论】:

标签: sql sql-server stored-procedures


【解决方案1】:

如果表在您的控制之下,则没有理由执行额外检查。假设它们设置正确,并让 SQL 处理任何错误。不断检查你是否确实做了你打算做的事情是过度防御性的编程,会给你的代码增加不必要的复杂性。

例如,你不会写这样的代码:

i = 1;

if (i != 1) 
{
    print "Error: i is not 1!";
}

我认为这种情况类似。

如果这些表不在您的控制之下,那么优雅地处理错误可能会很有用。例如,如果此过程可以在用户创建的任意一组表上运行,或者如果它将分发给需要在自己的数据库中设置表的外部用户,您可能需要添加一些自定义错误处理。这样做的目的是让用户更清楚地描述出了什么问题。

【讨论】:

    【解决方案2】:

    作为一个基本概念,在可能引发错误的代码之前验证值是一件好事。但是,在这种情况下,在存在检查和插入语句之间,表 a 或表 b 中可能(至少在理论上)发生变化,这会引发 fk 违规错误。

    我会这样做:

    BEGIN TRY
      INSERT AB (AId,BId) VALUES (@A,  @B)
      SELECT NULL As ErrorMessage
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE() AS ErrorMessage
    END CATCH
    

    ERROR_MESSAGE() 函数返回在 try 块中引发的错误。

    然后在执行代码中你可以简单地检查返回的错误信息是否为空。如果是,则您知道插入成功。如果没有,您可以按照自己认为合适的方式处理此异常。

    【讨论】:

    • 矫枉过正,除非您有实际理由相信其他人可能会在您的代码运行时更改表。
    • 无论如何你都必须处理这个错误,为什么不把它保存在 sql server 中呢?与处理客户端代码中的错误相比,这并不过分。
    • 无论您做什么,客户端代码都需要处理调用过程时引发 SQL 错误的一般情况。因此,专门处理此错误确实确实为您的代码添加了一些额外的东西——而且您还必须在客户端添加对该错误的额外处理,以便它产生任何影响。除非您有实际理由认为这些表可能设置不正确(例如,它们超出您的控制范围),否则这种错误处理在我看来过于防御性了。
    【解决方案3】:

    通常我会检查 Fk。如果 Fk 不存在,则友好地抛出错误,insert 语句不会被执行,数据库也不会锁表。

    【讨论】:

    • 这应该是一条评论。不是答案
    猜你喜欢
    • 1970-01-01
    • 2014-05-24
    • 1970-01-01
    • 2015-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    相关资源
    最近更新 更多