如何绕过SQL Server 2008上的触发器

时间:2012-03-01 12:39:23

标签: sql-server sql-server-2008 sql-server-2005 triggers

我想在某些情况下绕过触发器,任何人都可以帮助我吗?

我尝试使用this link,但无法找到解决方案。

提前致谢

6 个答案:

答案 0 :(得分:10)

步骤1禁用触发

DISABLE TRIGGER Person.uAddress ON Person.Address;

http://msdn.microsoft.com/en-us/library/ms189748.aspx

第2步做事

UPDATE Person.Address SET HouseNumber = REPLACE(HouseNumber, ' ', '');

步骤3启用触发

ENABLE Trigger Person.uAddress ON Person.Address;

http://msdn.microsoft.com/en-us/library/ms182706.aspx

- 必须说,小心使用!

答案 1 :(得分:8)

你无法避免触发器被运行。 您可以做的是在其中添加条件,例如:

CREATE TRIGGER trigger_name
   ON table
   AFTER INSERT 
AS
begin
   IF (your condition) begin
     --code
   END
end

如果你有一个INSTEAD OF触发器,请小心。如果您不对插入进行编码,则表格中不会插入任何内容。

答案 2 :(得分:3)

@Manish:我认为绕过触发器不是最佳实践视角的好选择。相反,我会评估,考虑并过滤掉触发器所需的一组条件。

答案 3 :(得分:3)

您可以通过检查是否存在临时表来抑制触发器。需要抑制触发器的代码应该创建临时表(比如#suppress_trigger)。在触发器中检查是否存在此临时表并返回。 例如:

CREATE TABLE [dbo].[dummy](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Val] [char](1) NULL)   

--create a history table which gets populated through trigger
CREATE TABLE [dbo].[dummy_hist](
[Id] [int] NULL,
[Val] [char](1) NULL) 

CREATE TRIGGER [dbo].[trig_Insert]
   ON  [dbo].[dummy]    
   AFTER INSERT
AS 
BEGIN

    SET NOCOUNT ON;
    if OBJECT_ID('tempdb..#Dummy_escape_trig') is not NULL
        RETURN

    INSERT INTO dummy_hist
    SELECT * FROM inserted

END

--Proc for which trigger needs to be suppressed
CREATE PROCEDURE [dbo].[ins_dummy]
        @val AS CHAR(1)
AS
BEGIN

    SET NOCOUNT ON;    

    CREATE TABLE #Dummy_escape_trig (id int)

INSERT INTO dummy
    VALUES(@val)
END

答案 4 :(得分:0)

在生产环境中禁用触发器存在一些实际问题。我假设您将专门禁用表触发器(与数据库或服务器范围内相反):

  1. 您需要对操作的表具有ALTER权限。出于安全原因,通常认为这是有问题的。在数据库和服务器级别,问题变得更加严重。
  2. 禁用不限于您的特定连接/会话,它会影响禁用该触发器的所有事件,无论这些会话触发任何触发器。如果您在所讨论的代码中期望并发,那么您必须假定将从其他线程调用相同的代码。早期建议中缺少的是充分考虑使用任何种类的信号量的并发管理。特别是,该临时表为代码的受保护部分(在多线程意义上)定义了一个信号量,其中该信号量是临时表的存在。如果您实际上禁用了触发器,然后为了正确使用该临时表以达到预期目的,则在受保护的代码创建临时表之前必须进行测试,以查看该临时表是否已经存在。这可能需要一个全局的临时表,或者您可以对tempdb进行更巧妙的搜索以查看它是否存在于任何会话中。受保护的代码必须测试信号灯是否存在,并且如果它打算等待资源(在本例中为触发器)按预期方式可用,则进入阻塞状态。这变得复杂,并且以交换的复杂性几乎没有价值。

意见:虽然禁用/启用触发器很容易,但是如果您确实将某些特定用例的一部分临时禁用,则有很多注意事项需要注意,因为这是在设计应该采用的并发管理策略。

除非您对并发管理的细节比较满意,或者除非您绝对不需要代码是可重入/并发的,否则,如果您使用DISABLE TRIGGER,您(偶尔会)会遇到问题,但是不要不要考虑这些因素。

考虑到所有这些,我看到的最安全的路径是不禁用触发器,使用本地临时表作为仅影响当前会话的信号灯,仔细编写退出代码,以确保在以下位置销毁临时表如已经建议的那样,在受保护的代码的末尾,但是它仍然需要一个检查/块,即使仅在同一连接上(尤其是在同一连接上并行执行时)才重要。最绝对安全的方法是为受保护的代码单独创建一个sproc。 sproc检查/阻止,然后继续执行(并且在阻止代码退出后,您需要检查死锁错误),创建临时表。由于在sproc返回时会破坏临时文件,因此受保护代码之外的任何路径都将处理该信号量。但是临时表在整个 session 中都可用-不仅在sproc中(在sproc运行时),甚至在批处理中。 SQL Server在单个会话上支持并行查询,因此在该会话的一个线程中创建的临时表在任何其他线程中都是可见的。这意味着可以在同一会话中在该存储过程之外看到它,实际上,可以在同一时间运行相同的代码。因此,在这种情况下您仍然需要真正的并发管理。

最后,我对令人费解的评论表示歉意。我发现几乎所有有关多线程和并发管理的讨论都变成了这种说法,因为尽管概念并不那么困难,但长期以来人们一直认为编码实践是微妙而脆弱的,并且容易出现开发人员错误。

答案 5 :(得分:0)

创建其他用户。然后在触发器中检查当前用户并执行。