使用LINQ是否可能导致SQL连接泄漏?

6
我认为使用LINQ时不可能出现SQL连接泄漏,但是NumberOfReclaimedConnections的Perfmon跟踪显示有很多,而且在高负载下有时会出现“超时。在从池中获取连接之前,已经超过了超时时间。这可能是因为所有的池化连接都在使用并且已达到最大池大小”的异常。
我们没有在DataContext上使用Dispose,因为我们使用了延迟加载。几篇文章和博客告诉我这不应该是问题。
但有时我们仍然会遇到这些异常。但是不可能每个LINQ查询都保持连接打开,否则我们会有更多的异常。
编辑
应用程序是一个WCF服务。
如果您查看LINQ的文档和大多数文章,它们声称不需要Dispose来释放连接。它们声称DataContext只保持连接打开所需的短时间。
3个回答

11

当您的 DataContext 没有被处理并保持存活时,相关的连接也会保持存活状态。数据库连接是非托管资源,所有非托管资源必须得到正确的处理和释放。

即使您使用延迟加载并且没有明确定义的范围,您仍应在逻辑单元完成后清理数据库连接。在 ASP.NET 应用程序中,这个最晚的时间点应该是在请求处理结束时 - 在 Globals.asax 文件的 Application_EndRequest 方法中。在 WCF 服务中,任何活动数据上下文都应该在每次服务方法调用结束时进行处理。

此方面的文档描述比较模糊,虽然大多数情况下,您可能不需要手动释放 DataContext,但似乎还存在一些情况,其中从连接加载的数据会让连接本身保持存活状态。确认这在您的情况下是否发生的最简单方法是进行测试。


4
我发现在进一步搜索后找到了这个问题和答案,其中提到linq可能会被欺骗而保持连接开启。
我编写了这个小测试代码来重现它。如果我只用foreach替换Enumerator,那么它就能正常工作,但是Enumerator会保持连接开启。
public Organisation RunTestQuery2()
{
    IEnumerable<Organisation> orgs  = base.GetEntities<Organisation>().Take(5);

    var enumerator = orgs.GetEnumerator();
    int i = 0;


    while (enumerator.MoveNext())
    {
        var org = enumerator.Current;
        Debug.WriteLine(org.DescribingName);
        if (i == 3)
        {
           return org;
        }
        i++;
    }

    return null;
}

如果我在上下文中添加dispose调用,它们就会消失。

这只是编译器的魔法。foreach是实例化一个枚举器,调用MoveNext直到返回false,然后调用枚举器上的Dispose的语法糖。仅供参考。 - Kilanash

0

你的数据库是否出现了死锁?快速查看活动监视器应该会给你一些提示。

你如何管理DataContext的生命周期 - 你编写了什么样的应用程序(网站、Windows客户端、其他)?

一旦在查询或操作中使用,DataContext将保持连接,以便加载的实体可以进行延迟加载等操作,因此必须计划如何在应用程序中使用DataContext。

WCF服务...在这种情况下,我非常喜欢“每个请求一个上下文”的方法。我鼓励你在using()语句中包装数据操作,以便在完成后处理上下文。


我们目前没有死锁的问题,至少我所知道的是这样的,而且我们正在监控它。该应用程序是WCF服务,数据上下文不应该比服务调用的生命周期更长。 - Atle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接