处理SQL事务的并发尝试(特殊情况)

时间:2013-06-07 05:29:02

标签: c# asp.net sql-server stored-procedures transactions

我在SQL Server 2008R2数据库中有3个表,我需要一个接一个地填充他们的记录,所以我使用事务来完成这项工作没有问题。基本上我在事务中间有2个INSERT存储过程查询,以便在这些表中插入记录,如下面的代码所示;

  

该事务在ASP.NET的C#SqlTransaction类中处理。   以下程序仅用于事务中间。

第一张表:

ALTER PROCEDURE [INSERT_RESOURCE]
  @docID int,
  @resTitle nvarchar(500),
  @resCategory nvarchar(100),
  @resType nvarchar(50),
  @resLink nvarchar(MAX),
  @createdBy nvarchar(50),
  @createdDateTime datetime
AS 
BEGIN 
  INSERT INTO Resource
   VALUES(@resTitle, @resCategory, @resType, 
          @resLink, @createdBy, @createdDateTime)
END

第二张表:

CREATE PROCEDURE [INSERT_RESOURCE_DOCUMENT]
  @docName nvarchar(200),
  @docSize nvarchar(50),
  @docType nvarchar(50),
  @docPath nvarchar(MAX),
  @docTitle nvarchar(100),
  @uploadBy nvarchar(50),
  @uploadDateTime datetime
AS
BEGIN
INSERT INTO Document
        VALUES(@docName, @docSize, @docType, @docPath, 
                           @docTitle, @uploadBy, @uploadDateTime)

INSERT INTO Resource_Document         --Third table
    VALUES(
           (SELECT TOP 1 ResourceID FROM Resource  ORDER BY ResourceID DESC), 
           (SELECT TOP 1 DocID FROM Document  ORDER BY DocID DESC)
          )

上面的过程工作正常,但可能的问题可能是第三个过程,即使用前两个表的最后一个ID在第三个表中插入数据,但由于最后一个INSERT语句正在使用SELECT如果同时其他人使用相同的事务在前两个表中添加一些值,那么TOP 1查询可能会选择错误的ID。 所以我想知道如何在这次交易中解决问题?

我可以在第三个存储过程中使用其他方法从前两个表中获取这些ID吗?

2 个答案:

答案 0 :(得分:1)

这里的问题是范围。您希望在该事务期间获得该用户的最后插入值。您选择的前1个查询会破坏用户的范围,并可能为任何用户选择最后插入的值。

要保留在用户范围内,请利用SQL的方法范围。将所有这3个操作转换为单个存储过程,然后使用SCOPE_IDENTITY()方法获取上次插入此会话/用户的标识列的值。这将安全地保证用户不会获得彼此插入的值。

在此处阅读更多内容:http://msdn.microsoft.com/en-us/library/ms190315.aspx

答案 1 :(得分:0)

第三个脚本肯定会在同时添加两个记录时导致问题。

我认为您可以设置一个后触发器(对于资源上的每个插入)和一个更新后触发器(对于文档上的每个插入)。 或者您可以加入上述两个表格(资源& 文档),然后创建一个触发器,将数据添加到第三个表格( Resource_Document

供参考 - http://msdn.microsoft.com/en-us/library/ms189799.aspx