同一张表的两个不同更新触发器

7
如何防止在同一表上的相同事件上触发两个触发器之间的锁定问题?
我正在处理的数据库已经有一个加密的更新触发器,因此我无法修改它。我创建了另一个更新触发器来完成一些新任务,在数据库上直接测试时它可以正常工作,但是当我在前端应用程序上更新产品时,它就会失败。显然,当我的触发器处于活动状态时,两个触发器都会失败。我收到的消息类似于“文档已经打开,我将增加它的值”。
这是一个锁定问题吗? 相关问题中有人说我们可以在同一表上拥有多个触发器(对于同一事件)。
以下是我的触发器代码:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[tr_st_rep_update]
ON [dbo].[st]
AFTER UPDATE
AS
  BEGIN
      SET NOCOUNT ON;

      IF ( update(ref)
            OR update(design)
            OR update(u_update)
            OR update(u_ativo)
            OR update(stock)
            OR update(epv1)
            OR update(epv2)
            OR update(epv3)
            OR update(peso)
            OR update(u_catnv1)
            OR update(u_catnv2)
            OR update(u_catnv3)
            OR update(u_dpromoi)
            OR update(u_dpromof)
            OR update(u_destaque) )
        BEGIN
            IF (SELECT count(*)
                FROM   Inserted
                       INNER JOIN Deleted
                         ON Inserted.ststamp = Deleted.ststamp
                WHERE  inserted.u_ativo = 1
                        OR ( Deleted.u_ativo = 1
                             AND Inserted.u_ativo = 0 )) > 0
              BEGIN
                  INSERT INTO RepData
                              (id,
                               REF,
                               familia,
                               stock,
                               epv1,
                               epv2,
                               epv3,
                               peso,
                               u_accao,
                               imagem,
                               process)
                  SELECT Inserted.ststamp AS id,
                         Inserted.REF     AS REF,
                         Inserted.familia AS familia,
                         Inserted.stock   AS stock,
                         Inserted.epv1    AS epv1,
                         Inserted.epv2    AS epv2,
                         Inserted.epv3    AS epv3,
                         Inserted.peso    AS peso,
                         CASE
                           WHEN Deleted.u_ativo = 1
                                AND Inserted.u_ativo = 0 THEN 'd'
                           ELSE 'u'
                         END              AS u_accao,
                         Inserted.imagem  AS imagem,
                         0                AS process
                  FROM   Inserted
                         INNER JOIN Deleted
                           ON Deleted.ststamp = Inserted.ststamp
                  WHERE  inserted.u_ativo = 1
                          OR ( Deleted.u_ativo = 1
                               AND Inserted.u_ativo = 0 )
              END
        END
  END 

任何帮助将不胜感激。
更新:数据库为MSSQL 2008。

1
你能提供确切的错误信息吗?(如果消息不是英文,请至少提供错误号码)。“文档已经打开,我将增加它的值”听起来不像是 SQL Server 的错误消息。 - Martin Smith
除了这个信息,我没有得到任何其他信息,它甚至不是显示为错误而是信息消息。如果相关的话,该操作是产品库存更新。 - Fabio
1
如果是生产环境,请检查应用程序日志,信息应该已经记录下来了;如果不是,则在数据库上运行分析器,看看出了什么问题。 - WKordos
2个回答

16
使用触发器进行部署后的现场开发和定制是一种诱人但不好的想法,肯定会不断产生像这样的问题。
然而,鉴于此,首先:表可以有多个触发器,这不是问题所在。
第二,错误消息“文档已经打开,我将增加它的值”可能来自于您的客户端应用程序或其他(加密)触发器,而不是 SQL Server 错误消息。因此,您可以尝试将加密触发器设置为首先执行,或将您的触发器设置为最后执行。这可能不能解决问题,但它可能会将错误从加密触发器移动到您的触发器,以便更好地报告和/或管理该问题。
然而,从一开始,唯一可能会出现问题的是,如果另一个触发器也在写入RepData表格,那么您的双重写入可能会导致重复键违规。
触发器顺序可以通过sp_settriggerorder系统存储过程进行控制,文档在此处记录。

1
好的回答,谢谢!那么,我该如何管理触发器的执行顺序呢? - Fabio

2
问题解决了。
虽然我认为问题与表锁有关,但我不知道问题的来源,具体是在插入表上。
我改变了内部的选择语句,直接从st表中获取值,而不是从Inserted表中获取。
感谢大家。

1
啊,好的。这意味着另一个触发器正在修改[st]表行,这将反映在[st]中但不会反映在[inserted]中。我猜测这可能导致了其他地方的某些关键冲突(可能是在[RepData]中)。 - RBarryYoung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接