在SQL Server 2005中,有没有办法让触发器找出哪个对象负责触发触发器?我想用它来禁用一个存储的prodecure的触发器。
是否还有其他方法可以仅为当前事务禁用触发器?我可以使用以下代码,但如果我没有弄错,它也会影响并发事务 - 这将是一件坏事。
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
答案 0 :(得分:57)
我刚刚看到这篇文章最近在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)
答案 1 :(得分:6)
如果您的触发器导致应用程序出现性能问题,那么最好的方法是删除对表的所有手动更新,并要求所有更新都通过包含正确更新逻辑的插入/更新存储过程。然后你可以完全移除扳机。
如果没有别的办法,我建议拒绝表更新权限。
这也解决了重复代码的问题。在更新SP和触发器中复制代码违反了良好的软件工程原则,这将是一个维护问题。
答案 2 :(得分:4)
答案 3 :(得分:2)
由于您指示触发器包含处理所有更新的逻辑,甚至是手动更新,因此应该是逻辑所在的位置。您提到的示例,其中存储过程“将处理此逻辑”意味着重复的代码。此外,如果您想确保每个UPDATE语句都应用此逻辑而不管作者,那么触发器就是它的位置。当某人创作一个程序但忘记再次复制逻辑时会发生什么?在修改逻辑时会发生什么?
答案 4 :(得分: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
答案 5 :(得分:1)
不要禁用触发器。你是正确的,将禁用任何并发事务。
为什么要禁用触发器?它有什么作用?问题是触发问题的原因是什么?从数据完整性角度禁用跳跳器通常是一个坏主意。
答案 6 :(得分:1)
如果性能问题,请考虑重写触发器以提高性能。
答案 7 :(得分:1)
我对这一点感到好意思。一方面,我非常反触发,主要是因为除了问题帖子中链接的文章中所述的原因之外,我还有一个地方可以查找针对我的表执行的代码。
另一方面,如果你有逻辑来强制执行稳定和不可变的业务规则或跨表操作(比如维护历史表)那么将它变成触发器会更安全,所以过程作者和程序员不会需要处理它 - 它只是有效。
所以,我的建议是将必要的逻辑放在你的触发器中,而不是在这一个过程中,这将不可避免地增加到具有相同豁免的几个过程。
答案 8 :(得分:0)
我同意其他一些答案。不要禁用触发器。
这是纯粹的意见,但我避免像瘟疫这样的诱因。我发现很少有使用触发器来强制执行数据库规则的情况。在我的经历中有明显的边缘情况,我只有我的经验来做出这样的陈述。我经常看到用于插入一些关系数据的触发器(应该从业务逻辑中完成),用于将数据插入到报告表中,即对数据进行非规范化(可以通过事务外的进程完成),或者用于转换数据某种程度上来说。
触发器有合法用途,但我认为在日常业务编程中它们很少见。这可能对您当前的问题没有帮助,但您可以考虑完全删除触发器并完成触发器以其他方式执行的工作。
答案 9 :(得分:0)
我刚遇到同样的问题,并提出了以下解决方案,这对我有用。
创建一个永久数据库表,其中包含您要禁用的每个触发器的一条记录(例如refTriggerManager);每行包含触发器名称(例如strTriggerName ='myTrigger')和位标志(例如blnDisabled,默认为0)。
在触发器主体的开头,在refTriggerManager中查找strTriggerName ='myTrigger'。如果blnDisabled = 1,则返回而不执行其余的触发代码,否则继续触发代码完成。
在要禁用触发器的存储过程中,执行以下操作:
BEGIN TRANSACTION
UPDATE refTriggerManager SET blnDisabled = 1 WHERE strTriggerName ='myTrigger'
/ *更新拥有'myTrigger'的表,但要禁用它。由于refTriggerManager.blnDisabled = 1,'myTrigger'返回而不执行其代码。 * /
UPDATE refTriggerManager SET blnDisabled = 0 WHERE triggerName ='myTrigger'
/ *触发触发器的可选最终UPDATE代码。由于refTriggerManager.blnDisabled = 0,'myTrigger'完全执行。 * /
COMMIT TRANSACTION
所有这些都发生在一个事务中,因此它与外界隔离,不会影响目标表上的其他UPDATE。
有没有人发现这种方法有任何问题?
比尔
答案 10 :(得分:0)
您可以使用“ Exec ”功能来禁用和启用存储过程中的触发器。示例:EXEC ('ENABLE TRIGGER dbo.TriggerName on dbo.TriggeredTable')