【问题标题】:Is it possible to definitively identify whether a DML command was issued from a stored procedure?是否可以明确地确定 DML 命令是否是从存储过程发出的?
【发布时间】:2011-02-19 13:00:04
【问题描述】:

我继承了一个 SQL Server 2008 数据库,调用应用程序可以通过存储过程访问该数据库。

数据库中的每个表都有一个影子审计表,其中记录了插入/更新/删除操作。

对填充审计表的性能测试表明,使用OUTPUT 子句插入审计记录比使用触发器快 20% 左右,因此这已在存储过程中实现。

但是,由于这种设计无法跟踪通过直接针对表发出的 DML 语句直接对表所做的更改,因此还实现了触发器,它使用 @@NESTLEVEL 的值来确定是否运行触发器(假设因为所有通过存储过程运行的 DML 都将具有@@NESTLEVEL > 1)。 即触发代码的主体看起来像:

IF  @@NESTLEVEL =   1   -- implies call is direct sql so generate history from here
    BEGIN
... insert into audit table

这种设计是有缺陷的,因为它不会跟踪在动态 SQL 中执行 DML 语句的更新,或者@@NESTLEVEL 高于 1 的任何其他上下文。

谁能建议一个完全可靠的方法,我们可以在触发器中使用,仅当不是由存储过程触发时才执行它们?

或者这(我怀疑)不可能?

【问题讨论】:

    标签: sql-server sql-server-2008


    【解决方案1】:

    使用CONTEXT_INFO (Transact-SQL)。在过程中设置一个值以提醒触发器不记录任何内容:

    --in the procedure doing the insert/update/delete
    
    DECLARE @CONTEXT_INFO  varbinary(128)
    SET @CONTEXT_INFO =cast('SkipTrigger=Y'+REPLICATE(' ',128) as varbinary(128))
    SET CONTEXT_INFO @CONTEXT_INFO
    
    --do insert/update/delete that will fire the trigger
    
    SET CONTEXT_INFO 0x0 
    

    在触发器中检查 CONTEXT_INFO 并确定是否需要执行任何操作:

    --here is the portion of the trigger to retrieve the value:
    
    IF CAST(CONTEXT_INFO() AS VARCHAR(128))='SkipTrigger=Y'
    BEGIN
        --log your data here
    END
    

    对于任何只是进行恶意插入/更新/删除的人,他们不会设置 CONTEXT_INFO,触发器将记录更改。如果您认为流氓代码也会尝试使用 CONTEXT_INFO,您可能会喜欢您放入 CONTEXT_INFO 的值,例如表名或@@SPID 等。

    【讨论】:

    • 进行防御性编程并将您的令牌“添加”到可能已经在 CONTEXT_INFO 中设置的任何内容可能是明智的吗?同样,由于它是基于连接的,他们不应该在程序结束时清除他们的令牌吗?如果一个过程调用一个过程,你应该只在它不存在的情况下添加/清除它?可能会变得棘手,但听起来仍然非常可行。
    • @Philip Kelley,在上面的简单示例中,我通过执行SET CONTEXT_INFO 0x0 清除它,您可以在更改它之前存储它的值,然后再将其设置回来。您还可以推送/弹出值等。可能性几乎是无穷无尽的,这只是机制的一个简单示例,而不是一个完全全面的示例。
    • 谢谢 - 这是一个很好的解决方案。
    【解决方案2】:

    我不这么认为。有一个longstanding Connect item 可以访问调用堆栈

    【讨论】:

      猜你喜欢
      • 2013-09-07
      • 2019-01-29
      • 1970-01-01
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 2012-04-11
      • 1970-01-01
      相关资源
      最近更新 更多