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

时间:2009-03-19 17:19:06

标签: c# .net sql-server sql-server-2005 stored-procedures

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

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

SQL Server如何处理这个问题?它甚至允许(非方法)静态成员吗​​?如果是这样,它在记忆中保留了多长时间?在每次CLR呼叫之后垃圾收集所有内容吗?它如何处理并发?

5 个答案:

答案 0 :(得分:6)

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

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

我可以看到在具有多个程序集的SQL Server CLR环境中安全地使用静态变量的唯一方法是实际上只使用单个程序集。您可以将ILMerge实用程序与“UnionMerge”选项一起使用,将所有程序集打包为一个并合并具有相同名称的类。这应该保证对于给定的数据库,在您的单独程序集中,您的静态变量将像在独立应用程序中一样工作。我认为可以安全地假设应用程序域没有在每次请求时卸载和重新加载,但是你不能依赖它永远不会被卸载,因为只要有未处理的错误就会发生(至少如果它在不安全的模式下运行) )。

答案 1 :(得分:3)

如果使用“不安全”权限级别部署程序集,则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中使用这些东西并且它可以工作。

答案 2 :(得分:3)

不可想象;你可以创建静态成员。但是,对于readonly PERMISSION_SETSAFE EXTERNAL_ACCESS的程序集,需要将它们标记为UNSAFE。只有标记为PERMISSION_SET的程序集才能具有可写静态成员。这种限制是由于静态成员的本质:它们在线程和会话之间共享

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

应该可以预期,一旦加载,类(以及它所驻留的App Domain)将保留在内存中,直到SQL Server服务重新启动或{{1}}值更改为止。但这不能保证。根据此页面,Memory Usage in SQL CLR

  

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

所以关于静态成员的两个方面都是正确的:

  • 它们可用于缓存(非常酷)
  • 他们可能更危险:
    • 他们可能会导致意外行为
    • 他们可以占用记忆,因为没有固有的机制或自然事件来清理它们,因为班级保持活跃。

并且,可用于CLR例程的内存量根据SQL Server是32位还是64位以及您使用的是SQL Server 2005/2008/2008 R2还是使用SQL Server 2012/2014而有很大差异。更多信息关于SQLCLR必须使用多少内存,请查看SQL Server 2012 MemoryMemory Usage in SQL CLR(与第一个链接相同,在报价上方发布)。

答案 3 :(得分:1)

以下是我找到的一些信息。

Troubles with shared state and anonymous delegates in SQLCLR

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

答案 4 :(得分:0)

来自C#规范3.0(5.1.1)

  

静态变量出现   在执行静态之前   构造函数(第10.12节)   包含类型,并且不再存在   何时关联应用程序域   不再存在。

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