Sql server SQL Server中的临时表、会话和日志记录?

Sql server SQL Server中的临时表、会话和日志记录?,sql-server,linq-to-sql,Sql Server,Linq To Sql,我的问题是我的上下文(目前)只存在于我的应用程序中。我想将这个上下文推送到数据库中,比如说,如果有自定义SQL Server连接属性之类的东西,我想使用它 我的想法是在执行任何工作(特定于应用程序的SQL)之前创建一个带有上下文信息的#本地临时表,并编写触发器,从该临时表中获取信息,并在通用日志记录表中汇总 我读过——在试图弄明白这一点的时候——在SQL Server中,对于临时表有会话的概念。但是,我还没有找到任何关于SQL Server会话的确切构成的文档 我想了解一下谁最适合(从应用程序)

我的问题是我的上下文(目前)只存在于我的应用程序中。我想将这个上下文推送到数据库中,比如说,如果有自定义SQL Server连接属性之类的东西,我想使用它

我的想法是在执行任何工作(特定于应用程序的SQL)之前创建一个带有上下文信息的
#
本地临时表,并编写触发器,从该临时表中获取信息,并在通用日志记录表中汇总

我读过——在试图弄明白这一点的时候——在SQL Server中,对于临时表有会话的概念。但是,我还没有找到任何关于SQL Server会话的确切构成的文档

我想了解一下谁最适合(从应用程序)将上下文推送到数据库上,然后对其进行处理。e、 g.触发器等

我正在为我的数据库对象使用Linq2Sql,我有点不确定如何连接它,以便为每个
DataContext.SubmitChanges
相关连接设置适当的上下文。在我看来,这应该等同于在
SubmitChanges
之前执行的一些自定义SQL,但实际上
DataContext.ExecuteCommand
SubmitChanges
是两件不同的事情,我有什么保证,它是相同的连接或(会话,如MSDN上的SQL Server文档所述)

更新:详情
  • 该应用程序是一个web应用程序,上下文是一些属性以及经过身份验证的用户(也称为ASP.NET会话状态项)
  • 默认情况下我使用连接池,我打算禁用它
  • 解决方案不一定要灵活,但必须是健壮的(这就是为什么我要将内容移动到数据库服务器中,目的是维护可靠的审核信息)

自定义连接属性或会话上下文不是SQL server世界固有的内容

您的问题中没有关于您是否在应用程序中使用连接池的信息。但是,如果您有连接池,则无法保证当您执行两个命令时,它们将使用相同的物理连接(另一个.NET应用程序线程可能会请求一个新连接,并可以从池中获取该连接,该池以前由第一个线程使用,同时第一个线程将希望打开该连接,并将实际获得第二个连接)

对于连接池,“会话上下文”是您只需要在应用程序级别上跟踪的内容。如果您有一个桌面应用程序,您有一个解决方法:您可以创建一个表,在该表中,您将有主机名和与每个主机名相关联的其他属性(但我们需要假设每个客户端只启动一个会话)

通常,如果要使用触发器实现日志记录,则必须使用现有变量,即主机名、用户名、应用程序名、会话id、日期时间

我假设,如果应用程序具有与用户会话逻辑关联的某些属性(例如,与ASP.NET会话),则可以为每个新会话分配一个GUID,并将某些永久性(而非临时性!)写入会话表中包含此GUID和您希望用于日志记录的所有自定义属性。然后,对于所有重要的表,您应该添加GUID列,并强制代码填充所有修改/插入行的GUID列。在这种情况下,您将能够在触发器中使用此GUID和所有上下文数据

另一种方法是使用存储过程进行更新/删除,并在其中添加一个额外的GUID参数,并直接在存储过程中实现日志逻辑(因此您不必向所有表添加额外的列,brrrr)


但是,如果你真的需要所有的逻辑工作人员在数据库级上工作吗?为什么不在应用程序业务或数据级别上实现日志记录?考虑到你的一些客户可能想要重定向日志到文件而不是数据库,以提高性能。如果你用Log4NET或者甚至是用诊断、跟踪、重定向来进行日志记录。日志输出只是一个配置问题,而不是整个系统的重新设计。如果您希望在SQL表中包含日志,例如用于报告-将日志以CSV格式写入文件,然后使用某些作业将此数据导入SQL server,并在夜间(或服务器不太活跃时)运行此作业.

这是我的目标解决方案

钩住连接状态更改事件

using System.Data;

var db = new DataContext(); // Change to your typical DataContext 
db.Connection.StateChange += new StateChangeEventHandler(StateChange);
然后,实现StateChange,如下所示:

using System.Data;
using System.Data.SqlClient;

// State changed to Open
if (e.CurrentState == ConnectionState.Open)
{
    var conn = sender as SqlConnection;
    if (conn != null)
    {
        // Figure out what context applies
        int? loginID = null;
        if (Session.IsAuthenticated)
        {
            loginID = Session.Login;
        }
        // Create local temporary context table
        var cmd = new SqlCommand();
        cmd.Parameters.AddWithValue("@p0", loginID ?? 0);
        cmd.CommandText = @"SET CONTEXT_INFO @p0";
        cmd.Connection = conn;
        cmd.ExecuteNonQuery();
    }
}
不管是连接池还是SQL提供程序连接管理器,都是在使用连接之前,但在
Open()
之后,本地状态立即更改。Linq2Sql将立即结束会话
Close()
,因此,这非常有效

然后,若要获取上下文信息,请执行以下操作(只要是同一会话@@SPID即可),仅限SQL Server 2005及更高版本

DECLARE @pContextInfo int
SELECT @pContextInfo = CAST(context_info AS int) 
FROM sys.dm_exec_sessions
WHERE session_id = @@SPID

我知道围绕连接池和线程的问题,这就是我提出问题的原因。这本身并不是一个特别困难的问题,更多的是在适当的时候拦截数据上下文。我将用更多的信息更新这个问题,但我看不出你的有目的的解决方案在这里有什么帮助,我仍然需要成为一名专家能够分别区分每个连接。