外键约束冲突并发问题

时间:2016-08-02 23:03:16

标签: sql-server concurrency foreign-keys

认为我遇到的问题是并发问题,但我想我不太了解SQL Server事务,以确定该怎么做。

我有一个存储过程,它将一个新行插入一个表,然后使用该INSERT创建的ID在另一个表中创建一个记录,该表在RID上有一个外键约束:

INSERT INTO tbl_Registrations ...

DECLARE @RID int;
--get newly-created registration ID
SET @RID=(SELECT MAX(RID) FROM tbl_Registrations WHERE ...);
INSERT INTO tbl_RegistrationCertificates VALUES (@RID, 9);

这个存储过程是从网站上的用户交互中调用的,每次我测试它都可以正常工作。但是,每隔一段时间,我会从错误处理程序收到一封电子邮件,但有以下异常:

System.Data.SqlClient.SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_tbl_RegistrationCertificates_tbl_Registrations". 
The conflict occurred in ... table "dbo.tbl_Registrations", column 'RID'.
The statement has been terminated.

但是,我的用户要么坚持点击“更新”按钮,直到他们看到更改,或者即使消息显示The statement has been terminated,事务仍在进行,因为,使用电子邮件中的其他信息,我可以看到两个表实际上都已更新。

我知道我在这里没有提供大量信息,但是我找不到答案的重大问题是:

  1. 语句末尾的分号是否在T-SQL中执行任何操作?我刚刚注意到INSERT语句末尾没有分号。 (我通常把它们放在习惯之外,但我正在研究其他人建造的系统。)
  2. 对于那些了解SQL Server的人而言,这看起来像是一个并发问题吗?
  3. 如果它看起来像并发问题,我可以使用事务来减轻它,我该怎么做?
  4. 编辑:我刚刚意识到SP毕竟不是抛出错误的东西。网站中有另一个地方正在进行插入,而没有检查是否存在RID。不过,我很高兴我问了这些问题,因为我仍然不知道答案。

1 个答案:

答案 0 :(得分:1)

T-SQL将分号视为语句分隔符,但并不总是需要它。关于这一点的更深入的讨论可以在question中找到。

至于外键错误,您提供的存储过程可能会因为一些原因而使用一些改进。

首先,您很可能在这里使用交易。如果您不希望添加注册记录,除非还添加了注册证书记录,则整个操作应该在单个事务中。

其次,如果同时调用存储过程,则选择标识插入列的MAX值很容易成为并发问题的根源。想象一下线程A INSERTS但在线程B INSERT之前无法运行其SELECT MAX(RID)的场景。现在,线程A和B都会尝试将相同的值插入到tbl_RegistrationCertificates。

SCOPE_IDENTITY()函数将通过为您提供此存储过程中查询生成的最新标识值来帮助解决此问题。

一些更新的代码:

IP