我有一个具有以下架构的表 [File]
CREATE TABLE [dbo].[File]
(
[FileID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](256) NOT NULL,
CONSTRAINT [PK_File] PRIMARY KEY CLUSTERED
(
[FileID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
这个想法是 FileID 用作表的键,而 Name 是代表文件的完全限定路径。
我一直在尝试做的是创建一个存储过程,它将检查名称是否已被使用,如果是,则使用该记录,否则创建一个新记录。
但是,当我使用许多线程同时执行存储过程对代码进行压力测试时,我得到了不同的错误。
此版本的代码将创建死锁并在客户端上引发死锁异常。
CREATE PROCEDURE [dbo].[File_Create]
@Name varchar(256)
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION xact_File_Create
SET XACT_ABORT ON
SET NOCOUNT ON
DECLARE @FileID int
SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
IF @@ROWCOUNT=0
BEGIN
INSERT INTO [dbo].[File]([Name])
VALUES (@Name)
SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
END
SELECT * FROM [dbo].[File]
WHERE [FileID] = @FileID
COMMIT TRANSACTION xact_File_Create
GO
这个版本的代码我最终在 Name 列中获得了具有相同数据的行。
CREATE PROCEDURE [dbo].[File_Create]
@Name varchar(256)
AS
BEGIN TRANSACTION xact_File_Create
SET NOCOUNT ON
DECLARE @FileID int
SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
IF @@ROWCOUNT=0
BEGIN
INSERT INTO [dbo].[File]([Name])
VALUES (@Name)
SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
END
SELECT * FROM [dbo].[File]
WHERE [FileID] = @FileID
COMMIT TRANSACTION xact_File_Create
GO
我想知道执行此类操作的正确方法是什么?一般来说,这是我想使用的模式,其中列数据在单列或多列中是唯一的,并且另一列用作键。
谢谢