我在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吗?
答案 0 :(得分:1)
这里的问题是范围。您希望在该事务期间获得该用户的最后插入值。您选择的前1个查询会破坏用户的范围,并可能为任何用户选择最后插入的值。
要保留在用户范围内,请利用SQL的方法范围。将所有这3个操作转换为单个存储过程,然后使用SCOPE_IDENTITY()
方法获取上次插入此会话/用户的标识列的值。这将安全地保证用户不会获得彼此插入的值。
在此处阅读更多内容:http://msdn.microsoft.com/en-us/library/ms190315.aspx
答案 1 :(得分:0)
第三个脚本肯定会在同时添加两个记录时导致问题。
我认为您可以设置一个后触发器(对于资源上的每个插入)和一个更新后触发器(对于文档上的每个插入)。 或者您可以加入上述两个表格(资源& 文档),然后创建一个触发器,将数据添加到第三个表格( Resource_Document )