2017-08-07 126 views
0

使用的node.js + sequelize.js + MSSQL许多更新得到死锁错误

我做的每5秒3个线程许多更新〜30(一个表)。设备轮询。

获取

SequelizeDatabaseError: Transaction (Process ID 57) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

sequelize生成SQL

sql: 

SET IDENTITY_INSERT [DeviceCurrentData] ON; 

MERGE INTO [DeviceCurrentData] WITH (HOLDLOCK) AS [DeviceCurrentData_target] 
USING (
    VALUES (
     9, 
     N\ '28.300000\', 
     \ '2017-08-07 15:26:28.000\', 
     12 
     ) 
    ) AS [DeviceCurrentData_source]([Id], [Value], [DateStamp], [DevParamId]) 
    ON [DeviceCurrentData_target].[Id] = [DeviceCurrentData_source].[Id] 
WHEN MATCHED 
    THEN 
     UPDATE 
     SET [DeviceCurrentData_target].[Value] = N\ '28.300000\', 
      [DeviceCurrentData_target].[DateStamp] = \ '2017-08-07 15:26:28.000\', 
      [DeviceCurrentData_target].[DevParamId] = 12 
WHEN NOT MATCHED 
    THEN 
     INSERT (
      [Id], 
      [Value], 
      [DateStamp], 
      [DevParamId] 
      ) 
     VALUES (
      9, 
      N\ '28.300000\', 
      \ '2017-08-07 15:26:28.000\', 
      12 
      ) 
OUTPUT $ACTION, 
    INSERTED.*; 

SET IDENTITY_INSERT [DeviceCurrentData] OFF; 

'

+0

[This previous answer](https://stackoverflow.com/questions/7843733/confused-about-updlock-holdlock)可能会有所帮助。你使用HOLDLOCK会阻塞INSERT和UPDATE,而使用UPDLOCK只会阻塞UPDATE。你应该跟踪那个spid并且找出它是否是失败的'INSERT'或'UPDATE'。 – Phoenix

+0

我编写'Model.update(item,{Id:item.Id})',但sequelize.js生成'HOLDLOCK'。我写了'Model.upsert',也得到了死锁错误 –

回答

0

HOLDLOCK是一个表级锁。一旦发布,在HOLDLOCK事务完成之前,任何其他事务都不能修改表内容。 MERGE对于并发性并不好,因为它有多个阶段,其他事务可能陷入其中。

对于高并发性,您应该使用upsert。 (尝试更新,如果输出为空,则执行插入操作)。

此外,使用完整的聚簇索引键,更新最好针对单个行进行。如果您尝试更新多行或者您的过滤器未被索引覆盖,则它可能会升级为更大的锁并导致死锁。

缓解死锁是一个复杂的话题。祝你好运。

+0

Model.upsert也得到了死锁错误。用HOLDLOCK标题自动生成,我可以改变它吗? 当我使用C#和EntityFramework时,我没有这个错误 –

+0

是的,你可以删除保持锁。假设ID是您的主键字段,您不应该为此简单事务添加锁。另一个选项是删除/插入。而不是更新记录,删除它然后插入新的。 –