1

为了简单起见,这里是我正在尝试做的一个例子:

我用 C# 编写的 CLR 库(它是线程安全的,即使我没有在示例中显示它):

public static class MySP {

    private static Session _session;

    [Microsoft.SqlServer.Server.SqlProcedure]
    [SqlFunction]
    public static void Send(string destination, string message)
    {
        if(_session == null)
            _session = new Session();

        _session.SendMessage(destination, message);
    }

}

编译后,我将其导入我的 SQL Server(使用 Microsoft SQL Server Management Studio):

CREATE ASSEMBLY [MyDLL] FROM 'C:\MyDLL.dll' WITH PERMISSION_SET = UNSAFE;
GO

我导入存储过程:

CREATE PROCEDURE sp_Send (@DestinationName nvarchar(256), @MessageString nvarchar(max))
AS EXTERNAL NAME MyDLL.[NS.MySP].Send
GO

最后,我有一个调用存储过程的 SQL 脚本:

EXEC sp_Send "MyDestination","MyMessage"
GO

现在的问题是:每次我调用存储过程(如上所示)时,都会创建一个新的 Session 对象(我知道,因为我看到在另一端打开了多个 TCP 连接)。

如何阻止 SQL Server 多次加载我的库,以便它实际执行“静态”对象范例?我只希望创建单个“会话”,直到 SQL Server 进程终止,而不是每次调用存储过程时都创建一个静态对象。

谢谢你。

更多细节(不确定它们是否有必要):我的“会话”对象是从另一个库加载的(所以我在技术上加载了 2 个 DLL,但在上面的示例中只显示了一个以保持简单),然后依次包装(并加载)一个本机 DLL,不确定此信息是否相关,但我想我会添加它。

编辑:我还想补充一点,如果我在同一个 SQL 脚本中多次调用我的存储过程,则会创建一个 Session 对象。每次我用多个存储过程调用调用该脚本时,都会创建一个新的 Session 对象。

4

1 回答 1

1

我从未编写过 .NET 存储过程,但显然这是因为 SQL 服务器创建了多个 AppDomain(或加载一个 AppDomain 并在过程执行完成后卸载它)。您应该能够在 SQL 服务器日志中看到 AppDomain 活动。

从我用谷歌搜索的一点点来看,SQL 服务器应该只为每个数据库加载一个 AppDomain。可能是您编写的代码以某种方式引发了未处理的异常,从而导致 AppDomain 卸载(并且在再次调用该过程时服务器重新加载它)。

也有可能是 SQL server 处于内存压力之下,在这种情况下它会卸载 AppDomain 以节省内存。

我认为您不能保证 SQL 服务器中只有一个 Session 对象,但您可以最大限度地减少创建新会话的次数。如果您想完全控制会话的生命周期,您必须自己托管它(可能在通过 WCF 公开会话的 Windows 服务中,并让 SQL 服务器连接到该服务以便与会话交互)。只要 SQL Server 是主机 - 您的会话就遵循它的规则......

(话又说回来,可能只是我读到的信息有误,SQL server 的 AppDomain 管理方式不同)

于 2014-02-19T20:59:32.617 回答