【问题标题】:Two different update triggers for the same table同一张表的两个不同的更新触发器
【发布时间】:2013-01-18 16:50:30
【问题描述】:

如何防止在同一张表上的同一事件触发的两个触发器之间出现锁定问题?

我正在处理的数据库已经有一个加密的更新触发器,因此我无法修改它。我制作了另一个更新触发器来完成一些新任务,当我直接在数据库上测试它时它工作正常,但当我在前端应用程序上对产品进行更新时失败。显然,当我激活触发器时,两个触发器都失败了。我收到的消息类似于“文档已打开,我将增加它的值”。

这是一个锁定问题吗?

有一个related question 有人说我们可以在一张桌子上拥有多个触发器(针对同一事件)。

这是我的触发器代码:

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

【问题讨论】:

  • 您能否给出准确 错误消息(如果消息不是英文,至少给出错误号)。 “文档已经打开,我将增加它的值”听起来不像是 SQL Server 错误消息。
  • 我没有收到任何其他消息,它甚至没有显示为错误,而是一条信息消息。该操作是产品库存更新(如果相关)。
  • 如果是生产,检查它必须写在某处的应用程序日志,如果不是在数据库上运行分析器,看看发生了什么

标签: sql-server tsql triggers


【解决方案1】:

使用触发器进行部署后的现场开发和定制是一个诱人的想法,但一开始是个坏主意,而且无疑会不断为您带来类似的问题。

但是,鉴于此,首先:表可以有多个触发器,这不是问题。

其次,错误消息“Document is already open, I'll increase it's value”来自您的客户端应用程序或其他(加密)触发器,它不是 SQL Server 错误消息.鉴于此,您可能可以尝试将加密触发器设置为首先执行,或者将您的触发器设置为最后执行。这可能无法解决问题,但它可能将错误从加密触发器移到触发器中,以便您更有机会以可管理的方式报告和/或解决它。

尽管副手,但可以从您的触发器中看到的唯一问题是,如果另一个触发器也在写入 RepData 表,并且您的双重写入导致重复键违规。


可以通过sp_settriggerorder 系统过程控制触发顺序,该过程记录在here

【讨论】:

  • 很好的答案,谢谢!那么,如何管理触发器的执行顺序?
【解决方案2】:

问题解决了。

我真的不知道问题的根源,尽管我认为这与表锁定有关,在这种情况下是在 Inserted 表上。

我只是更改了内部选择语句,以便直接从 st 表而不是 Inserted 中获取值。

谢谢大家。

【讨论】:

  • 啊,好的。这意味着另一个触发器正在修改 [st] 表行,这将反映在 [st] 而不是 [inserted] 中。我的猜测是,这会在其他地方(可能在 [RepData] 中)造成一些关键违规。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多