【问题标题】:How to store UserName who is Updating the value of a table in For Update Trigger?如何在更新触发器中存储正在更新表值的用户名?
【发布时间】:2013-11-11 08:06:01
【问题描述】:

在我的 Web 应用程序中,我正在创建一个日志进程。我创建了一个更新触发器,它工作得很好,但我需要知道谁更新了这个数据,即执行这个操作的用户。

我已经用谷歌搜索并要求使用 context_info。什么意思?

如何将这些信息存储在触发器表中?

这是我的程序..我使用了你的概念..

ALTER Procedure [dbo].[MIS_CompOffDate]   
(  
@EmpId nvarchar(20), 

@UserName nvarchar(50),

@ActualDate datetime,

@DayName nvarchar(20),

@CompOffDate datetime 

)  

As

Begin 

DECLARE @UserNameConverted VARBINARY(128) = CONVERT(VARBINARY(128), @EmpId);

SET CONTEXT_INFO @UserNameConverted;  

INSERT INTO MIS_BM_CompOff values(@EmpId, @UserName, @ActualDate, @DayName, @CompOffDate)

End

在empid中——用户的empid就在那里……

【问题讨论】:

  • 哪个用户? SqlServer 用户? Web 认证用户 ?它们是一样的吗?
  • 除非是数据库用户进行更新,否则为什么不使用触发器,而让应用程序进行更新?
  • @RaphaëlAlthaus Web 认证用户,不,他们不一样
  • 所以没有办法用触发器来获取它们(我会说)。
  • @RaphaëlAlthaus,那么如何实现这个概念的任何建议..

标签: sql sql-server triggers sql-server-2012


【解决方案1】:

我遇到了同样的问题,并在 SO 中使用了一些答案来解决这个问题。我创建了一个存储过程sp_SetConnectionUsername 来保存用户名,并创建了一个函数f_GetConnectionUsername,可以在触发器中使用它来检索用户名。因为CONTEXT_INFO 以二进制形式存储数据,所以需要进行一些小技巧才能将varchar 数据从中取出。请注意CONTEXT_INFO 的限制为 128 个字节(即 128 个字符)。

这是在从应用程序打开连接以设置用户名时调用的存储过程:

CREATE PROCEDURE [dbo].[sp_SetConnectionUsername]
    @username varchar(128)
AS
BEGIN
    -- Convert username varchar into binary
    DECLARE @binaryUsername varbinary(128)
    SET @binaryUsername = CAST(@username as varbinary(128))
    SET CONTEXT_INFO @binaryUsername
END

这是在触发器中调用以检索用户名的函数:

CREATE FUNCTION [dbo].[f_GetConnectionUsername]()
RETURNS varchar(128)
AS
BEGIN
    DECLARE @username varchar(128)

    -- Get binary from CONTEXT_INFO, convert to varchar, then remove all Char(0) 
    -- empty characters from it (these are used as spacing in binary). Otherwise,
    -- if CONTEXT_INFO has not been set, return the SQL Server username.
    IF CONTEXT_INFO() IS NOT NULL
        SET @username = REPLACE((select cast(CONTEXT_INFO() as varchar(128))) COLLATE 
            Latin1_General_BIN, CHAR(0), '')
    ELSE
        SET @username = SYSTEM_USER

    RETURN @username
END

希望对某人有所帮助。

【讨论】:

  • 我正在寻找 SESSION_CONTEXT 的替代方案,它在 SQL Server 2012 中不可用。这很好用。
【解决方案2】:

您可以使用触发器将SYSTEM_USERUSER_NAME() 插入到表中。 因此,触发触发器的任何操作都将使用该人的登录名或用户名执行该操作。 这是内部数据库。但是对于 Web 应用程序,您可以在任何成功登录后的变量中以及在任何更新中使用存储过程的变量中保存执行人的登录名信息,并且请求的参数之一应该是该登录参数。

【讨论】:

  • 我已经尝试过了,它会单独存储数据库用户名我需要对我的表进行更新操作的 Web 应用程序用户
  • 哦,这是在数据库里面。但是对于网络,您可以在任何成功登录后的变量中以及在任何更新中使用存储过程的变量中保存执行人的登录名信息,并且请求的参数之一应该是该登录参数。
  • 好的,我将用户名存储在过程参数中。如何在触发器函数中获取该登录参数并存储我的触发器表
  • 在这种方法中不需要触发器和存储过程来做到这一点。触发器供内部使用。
【解决方案3】:

这可以按照以下步骤完成:

  1. 将用户 ID 或名称传递给您的更新函数/过程
  2. 在更新功能/程序中将用户 ID 或名称设置为共享 像这样使用SET CONTEXT_INFO 的变量:

    SET CONTEXT_INFO @UserID
    
  3. 在您的触发器中,使用 CONTEXT_INFO() 函数提取 ID:

    DECLARE @UserID BIGINT = COALESCE(CAST(CAST(CONTEXT_INFO() AS BINARY(8)) AS INT),0)
    

【讨论】:

  • 我猜你做错了什么。你遵循这些步骤吗?您遇到什么错误?
  • SET CONTEXT_INFO 选项需要 varbinary (128) NOT NULL 参数。这是我的错误。我正在从 c# 传递 userid 的值并尝试将 UserId(EmpId of varchar datatype) 存储在过程中。我用上面的编码只设置了context_info @userid。
  • @user2941383 该错误表明您正在尝试将 NULL 值设置为 CONTEXT_INFO。因此,@UserID 未初始化。检查这个:DECLARE @UserID BIGINT = 1001; SET CONTEXT_INFO @UserID; SELECT COALESCE(CAST(CAST(CONTEXT_INFO() AS BINARY(8)) AS INT),0);
  • UserId(Empid) 是 varchar 类型,您直接分配值,而不是我需要从后面的 c# 代码中获取,即在过程参数中分配..
  • 检查是否正确传递。无论如何,您可以按如下方式存储和文本值:DECLARE @UserName VARCHAR(128) ='user2941383'; DECLARE @UserNameConverted VARBINARY(128) = CONVERT(VARBINARY(128), @UserName); SET CONTEXT_INFO @UserNameConverted; SELECT CAST(CAST(CONTEXT_INFO() AS VARBINARY(128)) AS VARCHAR(128));
【解决方案4】:

触发器只会知道您对表所做的更改,它不会知道实际插入/更新等外部的信息。

您最好从您的应用程序中处理它并将有关更新用户的信息与其他信息一起传递。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多