sql-server - 触发器导致死锁?

标签 sql-server sql-server-2008 triggers deadlock database-deadlocks

添加触发器后,我陷入了僵局。有一个 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上工作,就会发生死锁。有建议吗?

最佳答案

很老的问题,但我想如果其他人遇到它,我就找到了答案。当然是我的答案。

问题可能是 UserBalanceHistory 和 User 之间存在 FK 约束。在这种情况下,对 UserBalanceHistory 的两个并发插入可能会死锁。

这是因为在插入 UserBalanceHistory 时,数据库将在 User 上获取共享锁以查找 FK 的 ID。然后,当触发器触发时,它将对用户进行独占锁定。

如果这种情况同时发生,则这是一个经典的锁升级死锁,其中两个事务都无法升级为独占锁,因为另一个事务持有共享锁。

我的解决方案是在更新和插入时无偿加入到 User 表,并在该表上使用 WITH (UPDLOCK) 提示。

关于sql-server - 触发器导致死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6282501/

相关文章:

MYSQL - 用于将 VARCHAR 中的时间转换为 INTEGER 中的秒的触发器正在插入多行,而它应该只插入

mysql - 为 MySQL 数据库中的表创建触发器(语法错误)

sql - 为什么外部联接比单独查询慢

sql - 对分层数据进行 PIVOT

sql-server - 在非 SSIS 服务器上运行 SSIS 包时出错

sql - 如何在 SQL Server 上的 CASE 中使用 "IN"?

sql - 从字符串转换为uniqueidentifier时转换失败

sql - 从大型数据集中随机采样

python - 如何使用 TriggerDagRunOperator 触发 Airflow -dag

sql-server - SQL 代理命令行未保存