SQL Server CLR库存储过程静态对象多次实例化

时间:2014-02-13 15:32:33

标签: sql sql-server stored-procedures clr clrstoredprocedure

为了简单起见,这是我要做的一个例子:

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

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加载我的库,以便它实际上强制执行“静态”对象范例?我只想要创建单个“Session”,直到SQL Server的进程终止,而不是每次调用存储过程时都是一个静态对象。

谢谢。

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

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

1 个答案:

答案 0 :(得分:1)

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

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

SQL服务器也可能处于内存压力之下,在这种情况下,它将卸载AppDomain以节省内存。

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

(然后,可能只是因为我读过的信息是错误的,而SQL服务器的AppDomain管理是以不同的方式完成的)