【问题标题】:What's the workaround to pass parameters to triggers?将参数传递给触发器的解决方法是什么?
【发布时间】:2020-11-15 10:08:48
【问题描述】:

我在“合同”中有一个触发器,还有一个名为“审计”的表(不言自明)。

一切正常。如果我插入、编辑或删除,触发器会在 Audits 表中插入一行...

这里的问题是触发器不接受参数...而且我在 Audits 表中有一个名为“TriggeredBy”的表列...它应该具有用户 ID(插入、删除或更新)。

是否有我可以使用的解决方法,以便我可以将该值传递给该触发器?

【问题讨论】:

  • 是否可以选择使用 current_user 函数?
  • @Tarik 并不可悲(据我了解,它返回当前 SQL 用户的名称?)。用户不是 SQL 用户。每个人的 SQL 用户都是一样的
  • 使用存储过程可能是一种解决方案。我假设它是一个网络应用程序。
  • @Tarik 这是一个桌面应用程序,我正在使用存储过程插入...但是如何将存储过程准确链接到触发器?因为触发器应该自己运行。
  • 您是否在应用程序运行时保持打开的数据库连接,直到用户关闭应用程序?还是您打开连接、选择、更新或删除并关闭连接?

标签: sql-server


【解决方案1】:

如果您在应用程序期间打开了 db 连接,您可以通过使用带有 session if、user id 的表来跟踪谁与当前 db session 关联。

SessionId int, 用户 ID varchar(20)

在登录时,使用@@SPID 存储会话ID 和关联用户。

然后触发器可以使用@@SPID 并从表中检索用户 ID 并将其插入到日志表中。

选项 2: 使用应用程序角色。允许用户使用 Windows 集成安全性连接到 SQL 服务器数据库。调用 sp_setapprole 来设置角色。不应授予用户对任何表的访问权限。应用角色应该有插入更新删除。

您现在可以确定触发器中的用户。

【讨论】:

  • DBConnection 仅在用户执行查询时打开,然后再次关闭,所以我假设这不是可行的方法吗?您如何看待以下解决方案? docs.microsoft.com/en-us/sql/t-sql/statements/…
  • 嗯,上下文信息解决方案似乎是一个解决方案。然而,我认为应用程序角色更好。
  • @Tarik,如果您使用的是 SQL 2016 或更高版本,我建议使用 SESSION_CONTEXT 而不是 CONTEXT_INFO
【解决方案2】:

如果桌面应用程序使用 Windows 身份验证,您可以简单地使用 ORIGINAL_LOGIN()SUSER_SNAME() 在触发代码中获取最终用户帐户名称。

对于共享 SQL 登录,一种方法是将最终用户名存储在 SQL 会话上下文中以供触发器使用。会话上下文允许您使用sp_set_session_context 过程存储名称/值对,并使用SESSION_CONTEXT 函数读取当前会话值。在打开新的 SQL 连接后,使用当前用户名调用 sp_set_session_context,以便触发器可以使用它来识别最终用户。

下面的示例 T-SQL 代码。此外,请参阅 this answer 了解设置/使用会话级别值的其他方法。

CREATE TRIGGER TR_YourTable
ON dbo.YourTable
FOR INSERT, UPDATE, DELETE
AS
DECLARE @TriggeredBy sysname = COALESCE(CAST(SESSION_CONTEXT(N'end-user-name') AS sysname), N'unknown');
IF EXISTS(SELECT 1 FROM inserted) AND EXISTS(SELECT 1 FROM deleted)
BEGIN
    INSERT INTO dbo.YourAuditTable (Action, SomeColumn, TriggeredBy)
    SELECT 'updated', SomeColumn, @TriggeredBy
    FROM deleted;
END
ELSE
BEGIN
    IF EXISTS(SELECT 1 FROM inserted)
    BEGIN
        INSERT INTO dbo.YourAuditTable (Action, SomeColumn, TriggeredBy)
        SELECT 'inserted', SomeColumn, @TriggeredBy
        FROM inserted;
    END
    ELSE
    BEGIN
        INSERT INTO dbo.YourAuditTable (Action, SomeColumn, TriggeredBy)
        SELECT 'deleted', SomeColumn, @TriggeredBy
        FROM deleted;
    END;
END;
GO



--Example T-SQL usage. Queries should be parameterized in application code.
EXEC sp_set_session_context N'end-user-name', N'me';
INSERT INTO dbo.YourTable (SomeColumn) VALUES('example');
GO

【讨论】:

  • 谢谢,我会试一试。您如何看待创建临时表。 AFAIK 可以从触发器调用吗?
  • 你可以使用本地临时表,虽然这意味着如果它不存在触发器将失败。
  • 如果使用上下文解决方案,我不会使用 Windows 集成身份验证,因为它会使数据库完全打开。至于使用上下文解决方案,它要求每个到数据库的连接后都调用 sp_set_session_context。从安全的角度来看,这也可以通过反编译代码、获取共享用户和密码然后执行 sp_set_session_context 来模拟任何人来规避。应用程序角色并不完美,但如果有触发器记录更新,则可以让任何直接更新数据库的人承担责任。
猜你喜欢
  • 1970-01-01
  • 2021-01-07
  • 2022-11-11
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多