创建数据库连接-一次还是为每个查询执行一次?


101

目前,当我的网页首次加载时,我创建了一个数据库连接。然后,我处理页面并针对该连接运行任何查询。这是最好的方法吗?还是应该在每次运行查询时都创建数据库连接?

ps对我来说,创建1个连接并使用它更有意义,但我不知道这是否会引起任何其他问题。

我在MSSQL中使用C#(ASP.NET)。

Answers:


124

如果您为每个查询/事务创建一个,则管理“关闭”连接要容易得多。

我可以看到为什么常识指示您应该打开一个并在整个过程中使用它,但是会遇到连接断开和多线程的问题。因此,您的下一步将是打开一个包含50个连接的池,并使它们保持打开状态,并将它们分配给不同的进程。然后您会发现这正是.NET框架已经为您完成的工作

如果您在需要时打开一个连接,并在完成后将其处理,则实际上并不会关闭该连接,它只会将其返回到连接池中以再次使用。


当您发布时只是阅读该文章:)谢谢。
webnoob 2012年

2
您链接到的网页特定于SQL Server。连接到其他数据库(例如,Oracle,Sqlite,MySql)时,.NET是否还提供自动池化?
briddums'Mar

@briddums-我认为这取决于连接器。例如,.Net不提供MySql连接器。它是由MySql编写和维护的。虽然它可以工作,但以我的经验,较早的实现还远没有缺陷。
ZweiBlumen 2012年

1
@briddums:取决于提供程序程序集。我肯定Microsoft的Oracle实现和Oracle自己的都支持连接池,因为我已经使用了它们。我听说有一个MySql可以这样做,并且我希望Spring.NET中的提供程序支持池化,但是与直接询问或询问提供程序相比,最好不要问我。
pdr 2012年

1
应该知道,即使是在循环中,打开,运行查询和布置连接也要比一次打开并循环查询的速度一样快,有时甚至更快。总是处置。更安全,更快捷。不必担心从池中获得连接的开销,这是微不足道的。
smdrager 2012年

38

最佳实践是为每个查询创建一个连接-并且在显示数据的情况下,最佳实践是让查询一次性输入所有需要的数据。

背景资料:

在.NET中,SqlConnection.Open()默认情况下,调用将始终透明地使用连接池(请参阅MSDN上的SQL Server中使用连接池”)。因此,您只需使用即可建立新的连接Open(),并Close()在完成后进行调用,.NET会做正确的事。

请注意,如果没有连接池,则每个查询只能建立一个连接,因为创建实际的数据库连接可能会非常昂贵(身份验证,网络开销等),并且同时打开的连接数通常非常有限。


7
@webnoob-由于.​​NET使用连接池,因此不会。原因是连接可能会关闭,重新分配等-因此重用连接不是一个好习惯。
奥德

11
-1答案颇具误导性。为每个查询创建连接是一个非常糟糕的主意。您可能的意思是“从连接池中为每个查询检索一个新的连接”-但这与创建连接不同。
sleske 2012年

1
@sleske-与pdr的答案有何不同?
奥德

3
@Oded:啊,我明白了。在.NET中,调用SqlConnection.Open()将始终透明地使用连接池。因此,“打开连接”和“从池中检索连接”之间不存在区别。我的误会 我可以自由地在问题中添加一些解释,然后收回表决权。
sleske 2012年

2
@ eaglei22-它当然应该这样做(请参阅docs.microsoft.com/zh-cn/dotnet/framework/data/adonet/…)。通常,您可能希望尽快将连接返回到池中,但是,如果按顺序发出许多查询,则按照您的建议重用连接可能会更好。您需要测试并查看哪种方法更适合您(我不知道您使用的标准是什么,请同时检查两种方法并查看对所选指标的影响)。
Oded

0

请记住,所有这些都是在.Net生态系统的背景下进行的。

开发人员有时希望“优化”他们的代码以重新使用他们的连接对象。在这个问题的背景下,这几乎总是一个错误。

ADO.Net具有称为连接池的功能。当您创建并打开一个新的连接对象时,您真正要做的就是从池中请求连接。关闭连接后,会将其返回到池中。

重要的是要了解我们直接在代码中使用的对象:SqlConnection,MySqlConnection,OleDbConnectio等,它们都是由ADO.Net管理的真实基础连接的包装,而ADO.Net真实连接则“重”得多且价格昂贵从性能的角度来看。正是这些基础对象担心身份验证,网络传输,加密等问题,这些东西远远超过了您在自己的代码中实际看到的对象中的少量内存。

当您尝试重新使用连接对象时,将破坏ADO.Net有效管理重要基础连接的能力。您可以在小事情上获得效率,却要牺牲大得多的事情。

在应用程序或http请求之间重用连接也可能会迫使您意外地序列化某些本可以并行运行的内容,并成为性能瓶颈。我已经看到这种情况发生在实际的应用程序中。

在这里的网页示例中,您至少仅在单个http请求/响应的持续时间内保持较小的连接,通过评估您在请求管道中运行的查询并尝试获取它们尽可能减少对数据库的单独请求(提示:您可以在单个SQL字符串中提交多个查询,并使用DataReader.NextResult()或检查其中的不同表在DataSet它们之间移动)。

换句话说,与其考虑为应用程序或http请求重用一个连接,而不是针对每个查询重用一个连接,而是考虑每次调用数据库时都要使用一个连接……每次往返。然后尝试通过最小化这些行程的数量来最小化连接的数量。这样,您就可以满足两个目标。


但这只是一种优化。还可以优化程序员的时间,并获得有效的代码重用。开发人员不想一遍又一遍地编写相同的样板代码,只是想获得一个开放的,随时可用的连接对象。这不仅繁琐,而且是将错误引入程序的一种方式。

但是,即使在这里,每个查询(或往返)通常也要建立一个连接。您可以使用其他模式来避免重写相同的样板代码。这是我喜欢的一个示例,但还有许多其他示例


我参加这个聚会很晚,但是我认为这个答案涵盖了一些要点:)
Joel Coehoorn
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.