C# 什么是SQL Server CLR集成生命周期?

C# 什么是SQL Server CLR集成生命周期?,c#,.net,sql-server,sql-server-2005,stored-procedures,C#,.net,Sql Server,Sql Server 2005,Stored Procedures,如何在SQL Server中管理CLR(.NET)对象 SQL Server中任何CLR代码的入口点都是静态方法。通常,您将只创建存在于该方法范围内的对象。但是,可以想象,您可以将对对象的引用存储在静态成员中,让它们脱离方法调用范围。如果SQL Server跨多个存储过程/函数调用将这些对象保留在内存中,那么它们对于缓存应用程序可能很有用——尽管它们也会更危险 SQL Server如何处理此问题?它甚至允许(非方法)静态成员吗?如果是的话,它会在记忆中保留多久?它会在每次CLR调用后垃圾收集所有

如何在SQL Server中管理CLR(.NET)对象

SQL Server中任何CLR代码的入口点都是静态方法。通常,您将只创建存在于该方法范围内的对象。但是,可以想象,您可以将对对象的引用存储在静态成员中,让它们脱离方法调用范围。如果SQL Server跨多个存储过程/函数调用将这些对象保留在内存中,那么它们对于缓存应用程序可能很有用——尽管它们也会更危险

SQL Server如何处理此问题?它甚至允许(非方法)静态成员吗?如果是的话,它会在记忆中保留多久?它会在每次CLR调用后垃圾收集所有内容吗?它是如何处理并发的?

来自C#规范3.0(5.1.1)

一个静态变量开始存在 在执行静态 建造商(§10.12)的 包含类型,并且不再存在 当关联的应用程序域 不再存在


当然,它不会在每次调用后关闭整个应用程序域,因为这样会有点效率低下。因此,是的,只要数据库没有停止或重新启动,这些静态对象就会保留在那里。

以下是我找到的一些信息


不仅在非不安全程序集中不允许共享状态,而且匿名委托(很不幸)会触发此“共享状态”限制。

如果以不安全的权限级别部署程序集,SQL Server允许静态只读成员

实际上,对象将保留在内存中,直到SQL服务停止/重新启动

关于并发性,您的对象和方法应该像其他地方一样是线程安全的

例如:

public static class MyCLRClass
{
    private static readonly ReaderWriterLock rwlock = new ReaderWriterLock();
    private static readonly ArrayList list = new ArrayList();

    private static void AddToList(object obj)
    {
        rwlock.AcquireWriterLock(1000);
        try
        {
            list.Add(obj);
        }
        finally
        {
            rwlock.ReleaseLock();
        }
    }

    [SqlProcedure(Name="MyCLRProc")]
    public static void MyCLRProc()
    {
        rwlock.AcquireReaderLock(1000);
        try
        {
            SqlContext.Pipe.Send(string.Format("items in list: {0}", list.Count));
        }
        finally
        {
            rwlock.ReleaseLock();
        }
    }
}
我在SQL CLR中使用了这样的东西,它是有效的。

在Robin Dewson和Julian Skinner的“Pro SQL Server 2005程序集”中,它说加载到数据库中的程序集与其他数据库对象一样,由数据库用户拥有。同一数据库中同一用户拥有的所有程序集都将在同一AppDomain中运行。不同用户拥有的程序集将在单独的AppDomain中运行。“

这告诉我,如果您使用的是单个数据库,并且使用CREATE ASSEMBLY语句加载的所有程序集都具有相同的所有者,那么您的程序集都将在相同的应用程序域中运行。但是,在相同的应用程序域中并不意味着使用相同的代码库,因此即使相同的dll也可以加载到相同的ap中应用程序域多次出现,其类型将不匹配,即使它们具有相同的名称。当相同的命名类型来自不同的代码库时,它们的静态变量也将是不同的实例


要在SQL Server CLR环境中安全地将静态变量与多个程序集一起使用,我看到的唯一方法是只使用一个程序集“选项将所有程序集打包为一个程序集并合并具有相同名称的类。这应该保证对于给定的数据库,在您的唯一程序集中,静态变量将像在独立应用程序中一样工作。我认为,假设应用程序域没有在每次请求时卸载和重新加载是安全的,但你不能指望它永远不会被卸载,因为每当出现未处理的错误时(至少在不安全模式下运行时)就会发生这种情况;您非常可以创建静态成员。但是,对于具有
安全
外部访问
权限集
的程序集,它们需要标记为
只读
。只有标记为不安全的程序集才能具有可写静态成员。这种限制是由于静态成员的本质:它们在线程和会话之间共享

第一次访问程序集中的方法时,将加载该程序集。所有会话都可以使用它,这就是为什么只能访问静态方法。其思想是编写函数,而不是应用程序,因此在保持状态方面没有太多用处。而且,如果不同的会话相互覆盖,它很容易(尽管肯定不总是)导致不可预测的行为。因此,除非您自己编写该部分,否则根本不会处理并发性

应该预料,一旦加载,类(及其所在的应用程序域)将保留在内存中,直到SQL Server服务重新启动或
权限集
值更改。但这并不能保证。根据本页所述:

当服务器上存在内存压力时,SQL CLR将尝试通过显式运行垃圾收集并在必要时卸载appdomains来释放内存

因此,关于静态成员,您在这两方面都是正确的:

  • 它们可以用于缓存(非常酷)
  • 它们可能更危险:
    • 它们可能导致意外行为
    • 它们会占用内存,因为没有内在机制或自然事件来清理它们,因为类保持活动状态

而且,CLR例程的可用内存量因SQL Server是32位还是64位,以及您使用的是SQL Server 2005/2008/2008 R2还是SQL Server 2012/2014而异。有关SQLCLR必须使用多少内存的更多信息,请查看和(与第一个链接相同,张贴在报价上方)。

我希望不会,但希望看到专门针对SQL Server的明确的“是”或“否”(这肯定比典型的.NET运行时更受限制)@CraigWalker和Tamas:关于“是的,只要数据库没有停止或重新启动,这些静态对象就一直存在”,这是不正确的。AppDomains可以出于多种原因卸载,包括:1)由于内存压力而自动卸载,2)当程序集或数据库的安全设置更改时,3)如果有人执行
DBCC D