我有它独特的约束的表:
create table dbo.MyTab
(
MyTabID int primary key identity,
SomeValue nvarchar(50)
);
Create Unique Index IX_UQ_SomeValue
On dbo.MyTab(SomeValue);
Go
其代码是更好地重复检查(成功= 0,如果重复找到)?
选项1
Declare @someValue nvarchar(50) = 'aaa'
Declare @success bit = 1;
Begin Try
Insert Into MyTab(SomeValue) Values ('aaa');
End Try
Begin Catch
-- lets assume that only constraint errors can happen
Set @success = 0;
End Catch
Select @success
选项2
Declare @someValue nvarchar(50) = 'aaa'
Declare @success bit = 1;
IF EXISTS (Select 1 From MyTab Where SomeValue = @someValue)
Set @success = 0;
Else
Insert Into MyTab(SomeValue) Values ('aaa');
Select @success
从我的视图-我相信这一点Try/Catch
是错误的,并没有预期(如僵局甚至限制不希望重复时)。 在这种病例很可能有时用户会尝试提交重复,所以预计该错误。
我发现亚伦伯特兰文章认为明─检查重复并不慢得多,即使大多数刀片是成功的。
也有过网建议的负载使用的try / catch(避免2条语句不是1)。 在我的环境有可能是一样的未果的情况下1%,所以那种有道理了。
你有什么意见? 什么其他原因使用选项1或选项2?
更新:我不知道这是在这种情况下很重要,但表具有替代更新触发器(用于审计目的订立行删除也正好通过Update语句)。
我已经看到了文章,但请注意,低故障率我会更喜欢“JFDI”的格局。 我用这个之前高容量系统(40K行/秒)。
在阿龙的代码,你可以在高负载和大量写入下先进行测试时,仍然得到重复。 (这里解释dba.se )这一点很重要:你重复的还是发生了,只是不经常。 您还需要异常处理,并知道何时忽略重复的错误(2627)
编辑:在另一个答案简洁解释由瑞摩斯
不过,我想有一个单独的try / catch 只用于测试重复错误
BEGIN TRY
-- stuff
BEGIN TRY
INSERT etc
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627
RAISERROR etc
END CATCH
--more stuff
BEGIN CATCH
RAISERROR etc
END CATCH
首先,在EXISTS(SELECT ...)
是不正确的,它失败下并发:多个事务可以同时运行检查,所有的结论是他们必须插入,一个将成为幸运的获奖者是首先插入,其余全部将打击违反约束。 换句话说,你必须检查和刀片之间的竞争条件。 所以,你必须的try / catch 无论如何 ,所以更好的刚try / catch语句。
错误记录
请不要把我这一点,但有些时候抛出一个异常可能记录的影响。 如果您在插入前检查没有这样的事情发生。
知道为什么,当它可以打破
try / catch块应该用于能够打破非确定性的原因部分。 我会说这是你的情况比较明智的检查现有的记录,因为你知道它可以打破和到底为什么。 因此,检查它自己是从开发人员的角度来看一个更好的办法。
但是,在你的代码仍可能在插入时中断,因为之间的检查时间,并插入一些其他时间用户插入它已经......但事实(如前面说的)不确定性的错误。 这就是为什么你:
- 应与被检查
exists
- 中插入
try/catch
言自明代码
另一个积极的也是很普通的从代码为什么会破裂而try / catch块可以隐藏和一个可以删除它们想明白为什么会在这里,它只是插入记录 ...
选项 - 3
Begin Try
SET XACT_ABORT ON
Begin Tran
IF NOT EXISTS (Select 1 From MyTab Where SomeValue = @someValue)
Begin
Insert Into MyTab(SomeValue) Values ('aaa');
End
Commit Tran
End Try
begin Catch
Rollback Tran
End Catch
为什么不实行INSTEAD OF INSERT
在桌子上触发? 您可以检查是否此行存在,什么都不做,如果是的话,然后插入该行,如果它没有。