“打开/关闭” SqlConnection还是保持打开状态?


121

我用静态方法在简单的静态类中实现了我的业务逻辑。这些方法中的每一个在调用时都会打开/关闭SQL连接:

public static void DoSomething(string something)
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();

        // ...

        connection.Close();
    }
}

但是我认为避免打开和关闭连接会节省性能。我很久以前用OleDbConnection类(不确定SqlConnection)进行了一些测试,它确实可以像这样工作(据我所记得):

//pass the connection object into the method
public static void DoSomething(string something, SqlConnection connection)
{
    bool openConn = (connection.State == ConnectionState.Open);
    if (!openConn)
    {
        connection.Open();
    }

    // ....

    if (openConn) 
    {
        connection.Close();
    }
}

所以问题是-我应该选择方法(a)还是方法(b)?我读了另一个stackoverflow问题,即连接池为我节省了性能,我完全不必费心...

PS。这是一个ASP.NET应用程序-连接仅在Web请求期间存在。不是Win-App或服务。


1
只是一个建议:使用DbConnection.StateChange事件来监视连接状态更改(可能存储在本地)中的更改,而不是DbConnection.State直接检查属性。它将节省您的性能成本。
decyclone 2010年

1
缺少的一个细节是此方法如何成为页面请求的一部分。是唯一调用的方法还是它,正如我在响应中所假设的那样,是在页面请求中调用的许多方法之一,它影响哪个答案是正确的;)
DavidMårtensson2010年

大卫-很多这样的方法被称为:)
亚历克斯(Alex)2010年

1
案例(A)表示缺乏处置信仰:看stackoverflow.com/questions/1195829/...和MSDN上的例子msdn.microsoft.com/en-us/library/...
user2864740

Answers:


82

坚持选择a

连接池是您的朋友。


37
恕我直言-他甚至不应该关闭。处理将做到这一点。
罗伊·纳米尔

2
@RoyiNamir我有点喜欢关闭连接的呼叫。尤其适合初学者和新手使用。它更加明确和可读。
edhedges,2014年

27
@edhedges同时使用“ using”和Cl​​ose()只会对新手造成混乱。他们不会理解利用“使用”的目的。不要使用“关闭”,而是教他们“使用”的目的。这样他们可以学习变得更好,并将学到的知识应用到代码的其他部分。
路易斯·佩雷斯

1
应该/是否需要调用“ Open()”?我目前正在这样使用它:using(var conn = GetConnection()){} public SqlConnection GetConnection(){return new SqlConnection(_connectionString); }
ganders

79

每次使用方法(a)。当您开始扩展应用程序时,处理状态的逻辑将变得非常痛苦。

连接池按锡说的做。只需考虑一下在应用程序扩展时会发生什么,以及手动管理连接打开/关闭状态会有多困难。连接池在自动处理此方面做得很好。如果您担心性能,请考虑使用某种内存缓存机制,以防止任何阻塞。


33

处理完连接后,请务必立即关闭它们,以便它们的基础数据库连接可以返回到池中,并可供其他调用者使用。连接池的优化非常好,因此没有明显的损失。该建议与交易基本相同-完成后,请使其简短明了。

如果您在使用多个连接的代码周围使用单个事务遇到MSDTC问题,则情况将变得更加复杂,在这种情况下,您实际上必须共享连接对象,并且仅在完成事务后才关闭它。

但是,您在这里是手工做的,因此您可能需要研究为您管理连接的工具,例如DataSet,Linq to SQL,Entity Framework或NHibernate。


您通常不应该在每个方法调用中打开和关闭连接,对于每个页面请求只能打开一次。那就是我至少学到的知识;)打开和关闭会花费时间。
大卫·莫滕森(DavidMårtensson)2010年

8
@David Martensson-调用SqlConnection.Open时,连接实际上并未打开和关闭。当连接字符串与以前使用的连接字符串匹配时,ASP.NET从池中回收活动连接。这样做所涉及的开销是无关紧要的,此外,尝试“自己动手”意味着您必须承担所有管理任务,以确保连接在以后的每次使用中仍处于活动状态,这增加了复杂性和开销。对于连接池,最佳实践是为每次使用打开和关闭它。
Jamie Treworgy 2010年

2
出于我的敬意,答案“始终保持联系”并不十分适合这个问题……我确实关闭了它们。问题是-什么时候。
亚历克斯(Alex)2010年

@David Martensson“每个页面一次”被简化了。没错,如果您有多个数据库命令要一个接一个地执行,那么在执行它们时可以保持连接打开。如果您关闭并重新打开,则将有少量开销-连接将进入池中,稍后再从池中检索。
混凝土塘鹅

1
@David Martensson但不要保持空闲状态。如果您正在等待用户的操作或其他任何操作,请将其关闭。如有疑问,请将其关闭。您要尽可能快地打开,以希望其他人已经完成连接并将其合并。然后,您将退回您的青睐-尽您所能尽快关闭。
混凝土塘鹅

13

免责声明:我知道这很古老,但是我找到了一种简单的方法来证明这一事实,所以我投入了两美分。

如果您无法相信合并速度确实会更快,请尝试以下方法:

在以下位置添加以下内容:

using System.Diagnostics;
public static class TestExtensions
{
    public static void TimedOpen(this SqlConnection conn)
    {
        Stopwatch sw = Stopwatch.StartNew();
        conn.Open();
        Console.WriteLine(sw.Elapsed);
    }
}

现在更换所有通话Open()使用TimedOpen()和运行程序。现在,对于您拥有的每个不同的连接字符串,控制台(输出)窗口将具有一个长时间运行的打开状态,以及一堆非常快速的打开状态。

如果要标记它们,可以将其添加new StackTrace(true).GetFrame(1) +WriteLine


9

物理连接和逻辑连接之间存在区别。DbConnection是一种逻辑连接,它使用与Oracle的基础物理连接。关闭/打开DbConnection不会影响您的性能,但会使您的代码整洁稳定-在这种情况下,连接泄漏是不可能的。

另外,您还应该记住有关db服务器上并行连接存在限制的情况-考虑到这一点,有必要使连接非常短。

连接池使您无需进行连接状态检查-只需打开,使用并立即将其关闭即可。


是的,连接不是连接-即DbConnection不是物理连接。DbConnection是一个.NET类,它提供操作底层物理连接的方法和属性。
混凝土塘鹅

不幸的是,这并不是立即隐式完成所有操作,但是文档对此进行了详细说明。docs.microsoft.com/en-us/dotnet/framework/data/adonet/…–
奥斯汀·

2

通常,您应该为每个事务保持一个连接(没有并行计算)

例如,当用户执行收费操作时,您的应用程序需要首先找到用户的余额并进行更新,他们应该使用相同的连接。

即使ado.net有其连接池,调度连接成本也很低,但重用连接是更好的选择。

为什么不只在应用程序中保留一个连接

由于执行某些查询或命令时连接处于阻塞状态,因此这意味着您的应用程序仅同时执行一个数据库操作,这是多么糟糕的性能。

还有一个问题是,即使您的用户只是打开应用程序但没有任何操作,您的应用程序仍将始终具有连接。如果有很多用户打开您的应用程序,则db服务器将在所有用户未连接的情况下很快耗尽其所有连接源。任何东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.