关于数据库连接数问题的一点心得!!!请高手指正。

sim 2004-08-24 04:38:55
通过这几天的程序调试(在oracle和sql server下),我发现一个问题(不知道是不是我理解的问题):在一个应用中(exe),当你用connection建立连接的后,你在程序中用close是关闭不了的(是不是只是释放了本地的资源,并没有释放数据库的?请高手指点),我在oracle中试着建立了100多个连接,连完后马上close。结果在oracle中的连接是没有被释放的,只是处于inactive状态(这个是因为我的connection没有做任何的动作),直到我的应用关闭,oracle才彻底释放我建立的100多个连接。所以我觉得一个应用(exe)还是自己建立一个数据库操作的类比较好,在一般应用中使用一个连接就已经够了(在pb中就是只有一个sqlca连接,当然你可以自己另外建),在主程序中建一个public DBAcces dbop=new DBAccess();来操作数据库(这里的DBAccess就是自己建立的数据库操作类)。我觉得.net在这一点上很容易让初学者感到迷惑,不知道自己的应用到底需要多少连接(很多初学者多是从面板上直接拉connection控件,以至于每个访问数据库的窗口多建立了数据库的连接),个人觉得面板上的的数据库控件有点象摆设,自己写了数据库操作类,很多代码多要自己写,根本就用不到面板上的。
我是想到那里写到那里,语言可能有点不通顺,请大家见凉,以上纯属个人观点,错的地方希望高手能指点指点,先谢了!!
...全文
737 点赞 收藏 28
写回复
28 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
coofucoo 2004-08-25
高手们,你们很轻易就把俺给说晕了,
俺很轻松就知道俺有多菜了。
回复
sim 2004-08-24
这里我还有点不明白的地方就是 这里的连接池到底是数据库库端的还是客户应用程序中的?
所建立的连接池是只为你打开的 一个应用使用(建立连接池的应用),还是全局所有的应用多能使用?
回复
sim 2004-08-24
<<<<连接多的话消费的服务器资源就多,主要对数据库造成压力,对内存影响到不大。>>>>
在oracle 中就不是这样了,如果是专用服务器的话,他会为每个连接分配内存,大小有你的oracle配制文件定。
回复
ncucf 2004-08-24
呵呵,学习!

这就是说,在一个程序尚未退出,而且可能重新请求资源的时候,并不需要显式的释放连接资源,而交给服务器自己处理?

就是通常只要close就可以,而不用dispose?
回复
dazhu2 2004-08-24
学习!
回复
zhpsam109 2004-08-24
up!学习
!
回复
lgg06 2004-08-24
gz...
回复
firefight 2004-08-24
不同的应用环境需要不同的设计方式,如果存在大量用户并且连接时间很短,则最好使用连接池,不需要使用DISPOSE释放每个连接,以便重用连接,提高性能。如果连接数量固定,可以考虑释放资源。一般情况下我认为不必释放。
回复
eTopFancy 2004-08-24
搂主开头所说的数据库链接问题不足为奇,现在的开发工具做的程序基本上都这样,.net中也引入数据库链接池的概念,数据库连接池中的连接因连接串不同而异,即你在程序中用了多少个不同的连接串连接数据库,池里将存在多少个不同的连接,每个连接都有计数器,用户的请求先排队使用连接,计数器记载请求个数,资源不够的时候,再创建新连接;你的连接关闭的时候,往往是连接的计数器减1,当计数器为0时,连接池将保留一个连接以供用户的再次请求,你的程序关闭的时候,连接池将释放所有使用过的连接的资源。我说得很笼统,希望搂主看一下帮助或者书籍。
.net已经不再是简单的开发工具,而是一个面向对象的解决方案,其各个角落包括帮助都是面向对象的思想,以前大家都习惯了开发工具的单一向,不习惯.net的双重性功能——开发工具和解决方案,我觉得大家对.net的理解的力度远远不够,甚至相对来说有些肤浅,可能因为大家的目光只停留在.net作为一个开发工具而已。
这是我的个人看法,如有错处,请大家批评指正,
回复
13880079673 2004-08-24
我写一个数据库单建的类结构,通过这个类,可以保证只有一个连接

class DbOperator
{
private SqlConnection conn_;
private SqlCommand sqlCommand_;
private SqlDataReader reader_;
private static DbOperator operator_ = null;
private DbOperator()
{
string ConnStr = "Data Source=;Initial Catalog=;User ID = ;Password=;";
conn_ = new SqlConnection(ConnStr);
sqlCommand_ = conn_.CreateCommand(); }
public static DbOperator getInstance()
{
if (operator_ == null)
{
return new DbOperator(); }
return operator_;
}
private void closeInstanceImpl()
{
conn_.Close();
operator_ = null;
}
public void closeInstance()
{
operator_.closeInstanceImpl();
operator_ = null;
}
public SqlDataReader execQueryReader(string sql)
{
sqlCommand_.CommandText = sql;
reader_ = sqlCommand_.ExecuteReader();
return reader_;
}
public void execNoQuery(string sql)
{
sqlCommand_.CommandText = sql;
sqlCommand_.ExecuteNonQuery();
}
public void closeReader()
{
reader_.Close();
}
}

期调用格式为:
DbOperator.getInstance().execNoQuery("无返回结果的SQL语句")
或者
SqlDataReader reader = DbOperator.getInstance().execQueryReader("有返回结果的SQL语句")

回复
qimini 2004-08-24
今天看了用友的uferp8.5,打开企业门户后就建立了7,8个连接(整个应用退出后这7,8个连接才关闭(用sql server的性能监视器看的),用的过程中还有新打开连接的时候),感觉这样很不好,如果是单机版的还无所谓,如果有20个点呢?7*20可是个很大的数目,服务器的内存也是很贵的,呵呵。

>>>>>>

不会出现那种情况的(除非软件设计违背了ADO.NET的工作原理)。
1、正如楼上commandown(它山之石) 所说的,在小型程序中以及和数据库交互不是很频繁的程序中,建议在连接使用结束后就把它Dispose掉、释放其占用的资源。也就不会出现7*20了。

2、在大型的分布式应用系统中,我们必须要借助连接池来管理我们的连接。

<如果使用的是 OleDbConnection、OdbcConnection 或 OracleConnection 类,则连接池将由提供程序自动处理,所以您不必自己进行管理。果使用的是 SqlConnection 类,则连接池被隐式管理,但也提供选项允许您自己管理池。>
---MSDN 2003。
如何管理呢?下面的文字来自MSDN :

<*池的创建和分配
当连接打开时,将根据一种精确的匹配算法来创建连接池,该算法会使连接池与连接中的字符串相关联。每个连接池都与一个不同的连接字符串相关联。当新连接打开时,如果连接字符串不精确匹配现有池,则将创建一个新池。

在以下示例中,将创建三个新的 SqlConnection 对象,但只需要使用两个连接池来管理这些对象。请注意,第一个和第二个连接字符串的差异在于为 Initial Catalog 分配的值。

SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Integrated Security=SSPI;Initial Catalog=northwind";
conn.Open();
// Pool A is created.

SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Integrated Security=SSPI;Initial Catalog=pubs";
conn.Open();
// Pool B is created because the connection strings differ.

SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Integrated Security=SSPI;Initial Catalog=northwind";
conn.Open();
// The connection string matches pool A.
连接池一旦创建,直到活动进程终止时才会被毁坏。非活动或空池的维护只需要最少的系统开销。

*连接的添加
连接池是为每个唯一的连接字符串创建的。当创建一个池后,将创建多个连接对象并将其添加到该池中,以满足最小池大小的要求。连接将根据需要添加到池中,直至达到最大池大小。

当请求 SqlConnection 对象时,如果存在可用的连接,则将从池中获取该对象。若要成为可用连接,该连接当前必须未被使用,具有匹配的事务上下文或者不与任何事务上下文相关联,并且具有与服务器的有效链接。

如果已达到最大池大小且不存在可用的连接,则该请求将会排队。当连接被释放回池中时,连接池管理程序通过重新分配连接来满足这些请求。对 Connection 调用 Close 或 Dispose 时,连接被释放回池中。

警告 建议使用完 Connection 后始终将其关闭,以便连接可以返回到池中。这可以使用 Connection 对象的 Close 或 Dispose 方法来实现。不是显式关闭的连接可能不会添加或返回到池中。例如,如果连接已超出范围但没有显式关闭,则仅当达到最大池大小而该连接仍然有效时,该连接才会返回到连接池中。
注意 不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose。在终结器中,仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。有关更多信息,请参见垃圾回收编程。

*连接的移除
如果连接生存期已过期,或者连接池管理程序检测到与服务器的连接已断开,连接池管理程序将从池中移除该连接。请注意,只有在尝试与服务器进行通信后,才可以检测到这种情况。如果发现某连接不再连接到服务器,则会将其标记为无效。连接池管理程序会定期扫描连接池,查找已释放到池中并标记为无效的对象。找到后,这些连接将被永久移除。

如果存在与已消失的服务器的连接,那么即使连接池管理程序未检测到已断开的连接并将其标记为无效,仍有可能将此连接从池中取出。当发生这种情况时,将生成异常。但是,为了将该连接释放回池中,仍必须将其关闭。

*使用连接字符串关键字控制连接池
SqlConnection 对象的 ConnectionString 属性支持连接字符串键/值对,这些键/值对可用于调整连接池逻辑的行为。

下表描述了可用于调整连接池行为的 ConnectionString 值。

名称 默认值 说明
Connection Lifetime 0 当连接返回到池中时,将对它的创建时间和当前时间进行比较,如果时间间隔超过由 Connection Lifetime 指定的值(以秒为单位),则会毁坏该连接。在聚集配置中可以使用它来强制在运行服务器和刚联机的服务器之间达到负载平衡。
如果值为零 (0),则将使池连接具有最大的超时期限。

Connection Reset 'true' 确定在从池中移除数据库连接时是否将其重置。对于 Microsoft SQL Server 版本 7.0,如果设置为 false,将避免在获取连接时经历一个额外的往返过程,但必须注意的是连接状态(如数据库上下文)不会被重置。
Enlist 'true' 当为 true 时,如果存在事务上下文,池管理程序将自动在创建线程的当前事务上下文中登记连接。
Max Pool Size 100 池中允许的最大连接数。
Min Pool Size 0 池中维护的最小连接数。
Pooling 'true' 当为 true 时,将从相应的池中取出连接,或者在必要时创建连接并将其添加到相应的池中。 >
----------MSDN 2003


更详细的描述,你可以看看MS的官方文档~~~
回复
adailee 2004-08-24
public Categories(){
dsCommand = new SqlDataAdapter();
dsCommand.SelectCommand = new SqlCommand();
dsCommand.SelectCommand.Connection = new SqlConnection (DuwamishConfiguration.ConnectionString);
dsCommand.TableMappings.Add("Table", CategoryData.CATEGORIES_TABLE);
}

protected virtual void Dispose(bool disposing){
if (! disposing)
return;
if (dsCommand != null){
if(dsCommand.SelectCommand != null){
if( dsCommand.SelectCommand.Connection != null )
dsCommand.SelectCommand.Connection.Dispose();
dsCommand.SelectCommand.Dispose();
}
dsCommand.Dispose();
dsCommand = null;
}
}
}

这是Duwamish的一段代码,它可以避免连接数的问题。需要注意的是,它总是用下面的方法是用Categories的:
using (Categories accessCategories = new Categories()){
return accessCategories.GetCategories(categoryId);
}
也就是每次都及时调用Dispose()
回复
chenxing80 2004-08-24
要实现 IDisposable 接口
回复
guying999 2004-08-24
我看微软的例子里面都是派生自Dispose的,看来应该是先Dispose再Close
回复
chenxing80 2004-08-24
using (SqlConnection cn = new SqlConnection(connectionString))
{
cn.Open();
return ExecuteNonQuery(cn, commandType, commandText, commandParameters);
}

程序会自动调 cn 的 Dispose 方法
回复
liujiayu10 2004-08-24
至于释放的问题,我想最好养成习惯,用完及时关掉或释放!不管你用多少个连接
回复
firefight 2004-08-24
先Dispose()再Close(),还是先Close()后Dispose()呢?
另外Close()是在存在连接池设置的情况下不释放资源,如果不需要连接池,关闭连接池后Close()就应当是真正释放连接了。

回复
liujiayu10 2004-08-24
这就是面像对像啊,这些虽然也能开发出程序,甚至很不错的程序,但这样拖动控件,改变属性实现的数据库程序显然灵活性很差,不知道别人是不是喜欢用数据库控件的,我是从来不用的,大部分的东西全在代码里实现,用了Net以后,基本全用类装好,要用时调用一下即可,我觉得现在写数据库程序有以下几种:
1,拖控件,改属性,再绑定。这种是最不灵活的,但也是最简单直接的
2,每一个窗体或页面都是独立的,即,他们都独立的连数据库,谁也不继承谁,也不依靠谁
3,继承公共类,这种方法最灵活,也是Net的优势所在,代码共用,对于二次开发很方便

以上小结,不对之处,请大家 指正!谢谢1
回复
eboywy 2004-08-24
我的经验是:如果是WEB程序,自己写的数据库操作类一定要包含显示的释放资源和关闭连接的方法。如是WIN程序,尽可能少建连接。
回复
eboywy 2004-08-24
先Dispose()释放资源;再Close();应该就没问题了。

连接多的话消费的服务器资源就多,主要对数据库造成压力,对内存影响到不大。
回复
加载更多回复
相关推荐
发帖
C#
创建于2007-09-28

10.6w+

社区成员

.NET技术 C#
申请成为版主
帖子事件
创建了帖子
2004-08-24 04:38
社区公告

让您成为最强悍的C#开发者