【发布时间】:2011-06-08 17:04:36
【问题描述】:
添加触发器后,我遇到了死锁。有一个UserBalanceHistory 表,其中每个事务有一行和一个Amount 列。添加了一个触发器来对Amount 列求和,并将结果放在相关的User 表Balance 列中。
CREATE TABLE [User]
(
ID INT IDENTITY,
Balance MONEY,
CONSTRAINT PK_User PRIMARY KEY (ID)
);
CREATE TABLE UserBalanceHistory
(
ID INT IDENTITY,
UserID INT NOT NULL,
Amount MONEY NOT NULL,
CONSTRAINT PK_UserBalanceHistory PRIMARY KEY (ID),
CONSTRAINT FK_UserBalanceHistory_User FOREIGN KEY (UserID) REFERENCES [User] (ID)
);
CREATE NONCLUSTERED INDEX IX_UserBalanceHistory_1 ON UserBalanceHistory (UserID) INCLUDE (Amount);
CREATE TRIGGER TR_UserBalanceHistory_1 ON UserBalanceHistory AFTER INSERT, UPDATE, DELETE AS
BEGIN
DECLARE @UserID INT;
SELECT TOP 1 @UserID = u.UserID
FROM
(
SELECT UserID FROM inserted
UNION
SELECT UserID FROM deleted
) u;
EXEC dbo.UpdateUserBalance @UserID;
END;
CREATE PROCEDURE UpdateUserBalance
@UserID INT
AS
BEGIN
DECLARE @Balance MONEY;
SET @Balance = (SELECT SUM(Amount) FROM UserBalanceHistory WHERE UserID = @UserID);
UPDATE [User]
SET Balance = ISNULL(@Balance, 0)
WHERE ID = @UserID;
END;
我也开启了READ_COMMITTED_SNAPSHOT:
ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON;
我有一个并行进程正在运行,它正在创建UserBalanceHistory 条目,显然如果它同时在同一个User 上工作,就会发生死锁。有什么建议吗?
【问题讨论】:
-
我想让你明白你的触发代码非常糟糕和危险。您永远不能假设插入或删除只有一条记录。当有人第一次需要运行基于集合的插入(例如从新客户端导入历史数据)时,此代码会导致严重的数据完整性问题
-
是的,很好 - 我会解决这个问题。
标签: sql-server sql-server-2008 triggers deadlock database-deadlocks