2013-01-18 84 views
6

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

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

这是锁定问题吗?

有一个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

+1

你可以给出**精确的**错误信息(或者如果信息不是英文,至少是错误号码)。 “文档已经打开,我会增加它的值”听起来不像SQL Server错误消息。 –

+0

我没有得到任何其他信息,它甚至没有显示为错误,而是信息消息。如果相关,操作是产品库存更新。 – Fabio

+1

如果它的生产,检查应用程序日志,它必须写在某个地方,如果不运行分析器上的分析器,看看发生了什么 – WKordos

回答

0

问题已解决。

我真的不知道问题的根源,尽管我认为它与表锁定相关,在本例中是插入表上。

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

谢谢大家。

+1

啊,好的。这意味着另一个触发器正在修改[st]表行,这会反映在[st]中,而不是[inserted]中。我的猜测是,这会导致其他地方发生一些密钥违规(可能在[RepData]中)。 – RBarryYoung

8

使用触发器来完成部署后的现场开发和定制是一个诱人但却不好的主意,并且无疑会不断为您产生这样的问题。

但是,给定这个,然后第一个:表可以有多个触发器,这不是问题。

其次,错误消息“文档已经打开,我会增加它的值”是来自您的客户端应用程序或其他(加密)触发器,它不是SQL Server错误消息。鉴于此,可能您可以尝试将加密的触发器设置为先执行,或将触发器设置为最后执行。这可能不会解决问题,但它可能会将错误从加密的触发器移到触发器,您可以更好地以可管理的方式报告和/或解决问题。

虽然不适合,但是您的触发器可能会出现的唯一问题是,如果另一个触发器也在写入RepData表,并且您的双重写入导致重复密钥违规。


触发顺序可以通过sp_settriggerorder系统过程,这是记录here来控制。

+0

很好的答案,谢谢! 那么,我如何管理触发器的执行顺序? – Fabio

相关问题