36

在 SQL Server 2005 中,触发器是否有办法找出负责触发触发器的对象?我想用它来禁用一个存储过程的触发器。

有没有其他方法可以仅为当前事务禁用触发器?我可以使用下面的代码,但如果我没记错的话,它也会影响并发事务——这将是一件坏事。

DISABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ]

ENABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ]

如果可能的话,我想避免在我的表中使用“NoTrigger”字段并执行 的技术NoTrigger = null,因为我想让表尽可能小。

我想避免触发的原因是因为它包含对手动更新表很重要的逻辑,但我的存储过程会处理这个逻辑。因为这将是一个高度使用的过程,所以我希望它很快。

触发器在服务器上施加了额外的开销,因为它们启动了一个隐式事务。一旦执行触发器,就会启动一个新的隐式事务,并且事务中的任何数据检索都将锁定受影响的表。

来自:http ://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1170220,00.html#trigger

4

11 回答 11

60

我刚刚在 SQL Server Central 时事通讯上看到了这篇文章,它似乎提供了一种在连接上使用 Context_Info 可能有用的方法:

http://www.mssqltips.com/tip.asp?tip=1591


Terrapin 编辑:

上面的链接包括以下代码:

USE AdventureWorks;  
GO  
-- creating the table in AdventureWorks database  
IF OBJECT_ID('dbo.Table1') IS NOT NULL  
DROP TABLE dbo.Table1  
GO  
CREATE TABLE dbo.Table1(ID INT)  
GO   
-- Creating a trigger  
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE  
AS  
DECLARE @Cinfo VARBINARY(128)  
SELECT @Cinfo = Context_Info()  
IF @Cinfo = 0x55555  
RETURN  
PRINT 'Trigger Executed'  
-- Actual code goes here  
-- For simplicity, I did not include any code  
GO  

如果要阻止执行触发器,可以执行以下操作:

SET Context_Info 0x55555 
INSERT dbo.Table1 VALUES(100)
于 2008-10-07T12:22:26.550 回答
7

如果您的触发器导致应用程序出现性能问题,那么最好的方法是删除对表的所有手动更新,并要求所有更新都通过包含正确更新逻辑的插入/更新存储过程。然后您可以完全移除触发器。

如果没有其他方法,我建议拒绝表更新权限。

这也解决了重复代码的问题。在更新 SP 和触发器中复制代码违反了良好的软件工程原则,并且将成为维护问题。

于 2008-10-06T15:33:48.987 回答
4

ALTER TABLE tbl 禁用触发器 trg

http://doc.ddart.net/mssql/sql70/aa-az_5.htm

我不明白你第一段的意思

于 2008-10-06T15:13:28.403 回答
2

由于您指示触发器包含处理所有更新(甚至是手动更新)的逻辑,所以这应该是逻辑所在的位置。您提到的示例,其中存储过程“将处理此逻辑”意味着重复代码。此外,如果您想确保无论作者如何,每个 UPDATE 语句都应用了这个逻辑,那么触发器就是它的地方。当有人编写程序但又忘记复制逻辑时会发生什么?当需要修改逻辑时会发生什么?

于 2008-10-06T15:38:09.337 回答
2

不确定这是否是一个好主意,但它似乎对我有用。禁用触发器时,事务应防止从其他进程插入表。

IF OBJECT_ID('dbo.TriggerTest') IS NOT NULL
 DROP PROCEDURE dbo.TriggerTest
GO

CREATE PROCEDURE [dbo].[TriggerTest]
AS
BEGIN TRANSACTION trnInsertTable1s
;
DISABLE TRIGGER trg_tblTable1_IU ON tblTable1
;
BEGIN -- Procedure Code
    PRINT '@@trancount'
    PRINT @@TRANCOUNT
    -- Do Stuff

END -- Procedure Code
;
ENABLE TRIGGER trg_tblTable1_IU ON tblTable1

IF @@ERROR <> 0 ROLLBACK TRANSACTION
ELSE COMMIT TRANSACTION
于 2011-02-25T11:32:23.730 回答
1

不要禁用触发器。您是正确的,它将禁用任何并发事务。

为什么要禁用触发器?它有什么作用?为什么触发器会导致问题?从数据完整性的角度来看,禁用触发器通常是个坏主意。

于 2008-10-06T15:17:08.163 回答
1

如果性能是问题,请考虑重写触发器以提高性能。

于 2008-10-06T15:58:32.930 回答
1

我对此有点犹豫。一方面,我非常反触发,主要是因为除了问题帖子中链接的文章中所述的原因之外,我还有一个地方可以查找针对我的表执行的代码。

另一方面,如果您有执行稳定和不可变业务规则或跨表操作(如维护历史表)的逻辑,那么将其放入触发器会更安全,因此程序作者和程序员不需要处理有了它 - 它只是工作。

所以,我的建议是把必要的逻辑放在你的触发器中,而不是放在这个 proc 中,因为它不可避免地会增长到几个具有相同豁免的 proc。

于 2008-10-06T19:53:47.700 回答
0

我同意其他一些答案。不要禁用触发器。

这是纯粹的观点,但我避免像瘟疫这样的触发因素。我发现很少有使用触发器来强制执行数据库规则的情况。在我的经验中有明显的边缘案例,我只有我的经验可以做出这样的声明。我通常看到触发器用于插入一些关系数据(应该从业务逻辑中完成),用于将数据插入报告表中,即非规范化数据(可以通过事务外部的流程完成),或用于转换数据某种程度上来说。

触发器有合法用途,但我认为在日常业务编程中它们很少而且相差甚远。这可能对您当前的问题没有帮助,但您可能会考虑完全删除触发器并以其他方式完成触发器正在执行的工作。

于 2008-10-06T16:00:00.057 回答
0

我刚刚遇到了同样的问题,并提出了以下解决方案,这对我有用。

  1. 创建一个永久数据库表,其中包含您要禁用的每个触发器的一条记录(例如 refTriggerManager);每行包含触发器名称(例如strTriggerName = 'myTrigger')和一个位标志(例如blnDisabled,默认为0)。

  2. 在触发器主体的开头,在 refTriggerManager 中查找 strTriggerName = 'myTrigger'。如果 blnDisabled = 1,则返回而不执行其余的触发代码,否则继续触发代码直到完成。

  3. 在要禁用触发器的存储过程中,执行以下操作:


开始交易

更新 refTriggerManager SET blnDisabled = 1 WHERE strTriggerName = 'myTrigger'

/* 更新拥有“myTrigger”但您希望禁用的表。由于 refTriggerManager.blnDisabled = 1,'myTrigger' 在不执行其代码的情况下返回。*/

更新 refTriggerManager SET blnDisabled= 0 WHERE triggerName = 'myTrigger'

/* 触发触发器的可选最终更新代码。由于 refTriggerManager.blnDisabled = 0,'myTrigger' 完全执行。*/

提交交易


所有这些都发生在一个事务中,因此它与外界隔离,不会影响目标表上的其他 UPDATE。

有人看到这种方法有什么问题吗?

账单

于 2010-02-05T04:02:39.040 回答
0

您可以使用 ' Exec ' 函数来禁用和启用存储过程中的触发器。例子: EXEC ('ENABLE TRIGGER dbo.TriggerName on dbo.TriggeredTable')

于 2012-12-10T16:12:10.557 回答