我们有一个插入/更新/删除的存储过程,我们遇到一个问题,即用户有时会遇到死锁并丢失数据,这是因为另一个用户或实例正在使用存储过程或表。
表
CREATE TABLE [file].[ItemResourceFile](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Item_ID] [int] NOT NULL,
[ResourceFile_ID] [int] NOT NULL,
[IsDefault] [bit] NOT NULL CONSTRAINT [DF_ItemResourceFile_IsDefault] DEFAULT ((0)),
[Description] [nvarchar](max) NULL,
[DateTimeCreated] [datetime] NOT NULL CONSTRAINT [DF_ItemResourceFile_DateTimeCreated] DEFAULT (getutcdate()),
[DateTimeModified] [datetime] NOT NULL CONSTRAINT [DF_ItemResourceFile_DateTimeModified] DEFAULT (getutcdate()),
[CreatorUser_ID] [int] NOT NULL,
[LastModifierUser_ID] [int] NOT NULL,
[Status] [tinyint] NOT NULL CONSTRAINT [DF_ItemResourceFile_Status] DEFAULT ((0)),
[sequenceID] [int] NULL DEFAULT ('NULL'),
CONSTRAINT [PK_ItemResourceFile] PRIMARY KEY CLUSTERED
(
[Item_ID] ASC,
[ResourceFile_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [FILE]
) ON [FILE] TEXTIMAGE_ON [FILE]
GO
/****** Object: Index [IX_ItemResourceFile_ID] Script Date: 20-May-16 13:25:56 ******/
CREATE UNIQUE NONCLUSTERED INDEX [IX_ItemResourceFile_ID] ON [file].[ItemResourceFile]
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [FILE]
GO
/****** Object: Index [IX_ItemResourceFile_IsDefault] Script Date: 20-May-16 13:25:56 ******/
CREATE UNIQUE NONCLUSTERED INDEX [IX_ItemResourceFile_IsDefault] ON [file].[ItemResourceFile]
(
[Item_ID] ASC,
[IsDefault] ASC
)
WHERE ([IsDefault]=(1))
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [FILE]
GO
ALTER TABLE [file].[ItemResourceFile] WITH CHECK ADD CONSTRAINT [FK_ItemResourceFile_Item] FOREIGN KEY([Item_ID])
REFERENCES [file].[Item] ([ID])
GO
ALTER TABLE [file].[ItemResourceFile] CHECK CONSTRAINT [FK_ItemResourceFile_Item]
GO
ALTER TABLE [file].[ItemResourceFile] WITH CHECK ADD CONSTRAINT [FK_ItemResourceFile_ResourceFile] FOREIGN KEY([ResourceFile_ID])
REFERENCES [file].[ResourceFile] ([ID])
GO
ALTER TABLE [file].[ItemResourceFile] CHECK CONSTRAINT [FK_ItemResourceFile_ResourceFile]
GO
ALTER TABLE [file].[ItemResourceFile] WITH CHECK ADD CONSTRAINT [FK_ItemResourceFile_User] FOREIGN KEY([CreatorUser_ID])
REFERENCES [system].[User] ([ID])
GO
ALTER TABLE [file].[ItemResourceFile] CHECK CONSTRAINT [FK_ItemResourceFile_User]
GO
ALTER TABLE [file].[ItemResourceFile] WITH CHECK ADD CONSTRAINT [FK_ItemResourceFile_User1] FOREIGN KEY([LastModifierUser_ID])
REFERENCES [system].[User] ([ID])
GO
ALTER TABLE [file].[ItemResourceFile] CHECK CONSTRAINT [FK_ItemResourceFile_User1]
GO
SP
ALTER PROCEDURE [file].[usp_iudItemResourceFile]
@p_ItemID INT
, @p_ID INT = NULL OUTPUT
, @p_IsDefault BIT = NULL
, @p_Description NVARCHAR ( MAX ) = NULL
--, @p_RelPath NVARCHAR ( 2000 ) = NULL
, @p_Name NVARCHAR ( 250 ) = NULL
, @p_sequenceNumberID INT = NULL
, @p_Type TINYINT = NULL
, @p_Size INT = NULL
, @p_Status TINYINT = NULL
, @p_DoerTicket VARCHAR ( 200 ) = NULL
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @doerUserID INT
, @doerCompanyID INT
EXEC system.usp_validateAuthenticationTicket @p_Ticket = @p_DoerTicket
, @p_UserID = @doerUserID OUTPUT
, @p_CompanyID = @doerCompanyID OUTPUT
BEGIN TRANSACTION
IF ( @p_ID < 0 )
BEGIN
PRINT 'TBD'
END
DECLARE @res INT
EXEC @res = [file].usp_iudResourceFile @p_ID = @p_ID OUTPUT
--, @p_RelPath = @p_RelPath
, @p_Name = @p_Name
, @p_Type = @p_Type
, @p_Size = @p_Size
, @p_Status = @p_Status
, @p_DoerTicket = @p_DoerTicket
IF ( ( @@ERROR <> 0 ) OR ( @res <> 0 ) )
BEGIN
IF ( @@TRANCOUNT > 0 ) ROLLBACK TRANSACTION
RETURN 1050
END
IF ( ( @p_ID > 0 ) AND ( @p_IsDefault = 1 ) )
BEGIN
UPDATE [file].ItemResourceFile SET
IsDefault = 0
WHERE Item_ID = @p_ItemID
IF ( @@ERROR <> 0 )
BEGIN
IF ( @@TRANCOUNT > 0 ) ROLLBACK TRANSACTION
RETURN 1053
END
END
MERGE INTO [file].ItemResourceFile AS target
USING ( SELECT @p_ItemID
, @p_ID
, @p_IsDefault
, @p_Description
, @p_Status
, @p_sequenceNumberID
, @doerUserID
, @doerCompanyID ) AS source ( ItemID, ResourceFileID, IsDefault, Description, Status, sequenceID, DoerUserID, DoerCompanyID )
ON ( target.Item_ID = source.ItemID )
AND ( target.ResourceFile_ID = source.ResourceFileID )
WHEN MATCHED THEN
UPDATE SET
target.Description = NULLIF ( ISNULL ( source.Description, target.Description ), N'' )
, target.IsDefault = ISNULL ( source.IsDefault, target.IsDefault )
, target.Status = ISNULL ( source.Status, target.Status )
, target.sequenceID = source.sequenceID
, target.LastModifierUser_ID = source.DoerUserID
, target.DateTimeModified = GETUTCDATE ( )
WHEN NOT MATCHED BY TARGET AND source.ResourceFileID > 0 THEN
INSERT ( Item_ID
, ResourceFile_ID
, Description
, IsDefault
, Status
, sequenceID
, CreatorUser_ID
, LastModifierUser_ID )
VALUES ( source.ItemID
, source.ResourceFileID
, NULLIF ( source.Description, N'' )
, ISNULL ( source.IsDefault, 0 )
, ISNULL ( source.Status, 0 ) --0: Active
, source.sequenceID
, source.DoerUserID
, source.DoerUserID
)
WHEN NOT MATCHED BY SOURCE
AND target.Item_ID = @p_ItemID
AND target.ResourceFile_ID = ABS ( @p_ID ) THEN
DELETE;
IF ( @@ROWCOUNT <> 1 )
BEGIN
IF ( @@TRANCOUNT > 0 ) ROLLBACK TRANSACTION
RAISERROR ( 'DBException_ItemNotFound', 16, 1 )
RETURN 1060
END
--IF ( @p_ID IS NULL )
-- SET @p_ID = SCOPE_IDENTITY ( )
COMMIT TRANSACTION
RETURN 0
END
我该如何解决?