dispose()与close()的区别

                    dispose与close()的区别 

Dispose了,就必须再Create一次
而Close()后,还可以再Open(),
而Dispose后,对象都不存在了,就不能Open()了
Dispose是对于对象自身而言的,Close是对于连接数据库而言的
其它都是误导...

以下是相关知识点:

1.SqlConnection conn = new SqlConnection(strConnection)时,如果原来的连接已经关闭,此时需要开启一个新连接时,只要strConnection与上次的一样,就会又从连接池中取回原来的对象。Close时,SqlConnection的实例并不会被释放,它仅仅是被关闭了,并放置到了另一个地方,当下次需要时,会再次取出来。这样可以避免创建实例的开例。哈,不过,我认为这样的意义不是很大,只是.NET框架提供的一种管理优化机制而已(因为最消耗时间的还是Open与Close)

连接池允许应用程序从连接池中获得一个连接并使用这个连接,而不需要为每一个连接请求重新建立一个连接。一旦一个新的连接被创建并且放置在连接池中,应用程序就可以重复使用这个连接而不必实施整个数据库连接创建过程。

当应用程序请求一个连接时,连接池为该应用程序分配一个连接而不是重新建立一个连接;当应用程序使用完连接后,该连接被归还给连接池而不是直接释放。

数据库连接池中可能存在着多个没有被使用的连接一直连接着数据库(这意味着资源的浪费)。

使用连接池的最主要的优点是性能。创建一个新的数据库连接所耗费的时间主要取决于网络的速度以及应用程序和数据库服务器的(网络)距离,而且这个过程通常是一个很耗时的过程。而采用数据库连接池后,数据库连接请求可以直接通过连接池满足而不需要为该请求重新连接、认证到数据库服务器,这样就节省了时间。

包含在ADO.NET中的每个.NET数据提供程序都可实现连接池。

每一个连接池都与一个独立的连接字符串及其事务上下文关联。每次打开一个新的连接,数据提供者会尝试将指定的连接字符串与连接池的字符串进行匹配。如果匹配失败,数据提供者创建一个新的连接并将它加入连接池。连接池被创建之后,除非进程结束,否则不会被拆除。有人认为这种处理方式会影响性能,其实不然,维护一个不活动的或者空的连接池不需要多少开销。

连接池创建之后,系统会创建一些连接对象并将它们加入连接池,直至达到额定的最小连接对象数量。以后,系统会根据需要新建和加入连接对象,一直到达最大连接对象数量限额为止。如果程序请求一个连接对象时没有空闲的连接对象可用,且连接池里面的对象数量已达到上限,则请求被放入队列,一旦有连接被释放回缓冲池就立即取出使用。

注意:如果是并发访问里,一个连接正在被使用,而此时又启动了另一个进程或线程,则也会创建一个新的连接并放入连接池之中。只有第一次调用关闭后,第二次再次调用的时候,如果是相同的连接字符串,才会直接调用连接池中的连接。

关闭一个连接时,连接对象被返回给连接池以便重用,但这时实际的数据库连接并未被拆除。如果禁用了连接池,则实际的数据库连接也被关闭。这里必须强调的一点时,连接对象使用完毕后应当显式关闭并将它返回给连接池,不要依靠垃圾收集器来释放连接。

调用Close或Dispose方法可以将连接释放回连接池。只有当生存期结束或出现严重错误时,连接对象才会被从连接池删除。

对于.NET应用程序而言,默认为允许连接池。(这意味着你可以不必为这件事情做任何的事情)当然,如果你可以在SQLConnection对象的连接字符串中加进Pooling=true;确保你的应用程序允许连接池的使用。 ADO.NET默认为允许数据库连接池,如果你希望禁止连接池,可以使用如下的方式:
     1) 使用SQLConnection对象时,往连接字符串加入如下内容:Pooling=False;
     2) 使用OLEDBConnection对象时,往连接字符串加入如下内容:OLE DB Services=-4;

注意:在达到最小连接对象数量之前,是会不断创建新的连接对象的,另外,最大连接数量,实际上是指出了连接的并发数。

======================

static不保证你在多线程模式下仍是线程安全的,但总的来说,多一个连接的消耗在这里并不会造成什么影响,但有可能造成运行时的异常。将sqlConnection设置成static,一般情况下,不会有什么影响。
实际上在连接池之中,已经实际上类似单例的维护模式,所以,你即使是不断地new SqlConnection,也不会造成什么问题的。需要注意的是,维护一个长时间打开的SqlConnnection在WinForm里一般不会有什么问题,

===================================

ADO.Net连接池和连接字符串详细说明
Connection Pool 是什么呢 ?
每当程序需要读写数据库地时候。Connection.Open()会运用ConnectionString连接到数据库,数据库会为程序建立一个连接,并且维护打开状态,此后程序就可以运用T-SQL语句来查询/更新数据库。当执行到Connection.Close()后,数据库就会关闭当前地连接。很好,一切看上去均为如此有条不紊。

当然如果我地程序需要不定时地打开和关闭连接,(比如说 ASP.NET 或是 Web Service ),例如当Http Request发送到服务器地时候、,我们需要打开Connection 然后运用Select* from Table 返回一个DataTable/DataSet给客户端/浏览器,然后关闭当前地Connection。那每次都Open/Close Connection 如此地频繁操作对于整个系统择定确定就成了一种浪费。

ADO.Net Team就给出了一个比较好地解决方法。将先前地Connection保存起来,当下一次需要打开连接地时候就将先前地Connection 交给下一个连接。这就是Connection Pool。

-          Connection Pool 如何工作地?
首先当一个程序执行Connection.open()时候,ADO.net就需要判断,此连接是否支持Connection Pool (Pooling 默认为True),如果指定为False, ADO.net就与数据库之间创建一个连接(为了避免混淆,所有数据库中地连接,都运用”连接”描述),然后返回给程序。如果指定为True,ADO.net就会根据ConnectString创建一个Connection Pool,然后向Connection Pool中填充Connection(所有.net程序中地连接,都运用”Connection”描述)。填充多少个Connection由Min Pool Size (默认为0)属性来决定。例如如果指定为5,则ADO.net会一次与SQL数据库之间打开5个连接,然后将4个Connection,保存在Connection Pool中,1个Connection返回给程序。

当程序执行到Connection.close() 地时候。如果Pooling 为True,ADO.net 就把当前地Connection放到Connection Pool并且维护与数据库之间地连接。相应情况下还会判断Connection Lifetime(默认为0)属性,0代表无限大,如果Connection存在地时间超过了Connection LifeTime,ADO.net就会关闭地Connection相应情况下断开与数据库地连接,而不是重新保存到Connection Pool中。(这个设置重点用于群集地SQL 数据库中,达到负载平衡地目地)。如果Pooling指定为False,则直接断开与数据库之间地连接。

然后当下一次Connection.Open() 执行地时候,ADO.Net就会判断新地ConnectionString与原先保存在Connection Pool中地Connection地connectionString是否一致。(ADO.Net会将ConnectionString转成二进制流,所以也就是说,新地ConnectionString与保存在Connection Pool中地Connection地ConnectionString必须完全一致,即使多加了一个空格,或是修改了Connection String中某些属性地次序都会让ADO.Net认为这是一个新地连接,而从新创建一个新地连接。所以如果您运用地UserID,Password地认证方式,修改了Password也会导致一个Connection,如果运用地是SQL地集成认证,就需要保存两个连接运用地是同一个)。然后ADO.net需要判断当前地Connection Pool中是否有可以运用地Connection(没有被其他程序所占用),如果没有地话,ADO.net就需要判断ConnectionString设置地Max Pool Size (默认为100),如果Connection Pool中地所有Connection没有达到Max Pool Size,ADO.net则会再次连接数据库,创建一个连接,然后将Connection返回给程序。如果已经达到了MaxPoolSize,ADO.net就不会再次创建任何新地连接,而是等待Connection Pool中被其他程序所占用地Connection释放,这个等待时间受SqlConnection.ConnectionTimeout(默认是15秒)限制,也就是说如果时间超过了15秒,SqlConnection就会抛出超时错误(所以有时候如果SqlConnection.open()方法抛出超时错误,一个可能地原因就是没有及时将原先地Connnection关闭,相应情况下Connection Pool数量达到了MaxPoolSize。)如果有可用地Connection,从Connection Pool 取出地Connection也不是直接就返回给程序,ADO.net还需要检查ConnectionString地ConnectionReset属性(默认为True)是否需要对Connection 最一次reset。这是由于,原先从程序中返回地Connection可能已经被修改过,比如说运用SqlConnection.ChangeDatabase method 修改当前地连接,此时返回地Connection可能就已经不是连接当前地Connection String指定地Initial Catalog数据库了。所以需要reset一次当前地连接。当然由于所有地额外检查都会增大ADO.net Connection Pool 对系统地开销。


-          Connection Pool 如何设置呢?
要修改Connection Pool 唯一地方式就是通过设定Connection String来完成。

Pooling (true)
When true, the connection is drawn from the appropriate pool, or if necessary, created and added to the appropriate pool.
此属性代表是否需要运用到连接池,默认为True,如果指定为False,不运用连接池。

Connection Lifetime (0)
When a connection is returned to the pool, its creation time is compared with the current time, and the connection is destroyed if that time span (in seconds) exceeds the value specified by Connection Lifetime. This is useful in clustered configurations to force load balancing between a running server and a server just brought online.
A value of zero (0) will cause pooled connections to have the maximum time-out.
这个属性表示一个Connection地有效时间,如果一个Connection返回到ConnectionPool地时候,超过了Connection LifeTime时间,这个连接不会再次放到Connection。当下一个请求发来时,ADO.Net会新建一个Connection。
这个属性重点运用于群集地SQL数据库中,用于负载平衡。

Enlist (True)
When true, the pooler automatically enlists the connection in the current transaction context of the creation thread if a transaction context exists.

Max Pool Size (100)
The maximum number of connections allowed in the pool.

Min Pool Size (0)
The minimum number of connections maintained in the pool.

ConnectionReset (True)
Gets or sets a Boolean value that indicates whether the connection is reset when drawn from the connection pool.
The value of the ConnectionReset property or true if no value has been supplied.
This property corresponds to the "Connection Reset" key within the connection string.
当Connection从Connection Pool 中取回地时候,为了保证新地Connection 不会因为前一次

附带地提一下,在ADO.net 2.0 地世界中,修改SqlConnectionString 我们可以运用SqlConnectionStringBuilder类来完成


-          Connection.dispose() vs Connection.close()
可能所有人经常看到网络上有很多文档以及MSDN站点都推荐所有人运用using(sqlconnection cn=new sqlconnection()){}这样地方式来创建Connection,因为当超过{}后,.net framwork会自动执行Connection.dispose()方法,所以可以确保Connetion被及时地关闭。

1)那么及时地调用.dispose()真地这么重要么,如果一个对象超出了生存空间,在.net中不是会自动被GC(垃圾回收器)自动清理地么?

这个问题其实是由于GC导致地,.net中运用地GC,他对于工作并不像我们这样勤奋。GC只有当外界环境非常恶劣地时候(没有足够地内容分配地时候)他才会动手打扫卫生(清理不运用地对象)。所以对于Connection 即使超出了变量地生命周期,它可能还没有被GC干掉。依旧未将Connection返回给Connection Pool。
所以这就导致了下一个连接可能会有Connection Pool中没有Available地Connection而从新打开一个新地连接,无端地浪费了多余地性能。所以ADO.net team反复强调要及时地关闭当前地连接。一个最好地方法就是运用using{}block 系统会在退出{}地时候自动调用connection.dispose方法,而dispose会自动去执行close方法,释放当前地connection。

2)Dispose 到底做了些什么? protected override void Dispose(bool disposing)
...{
    if (disposing)
    ...{
        this._userConnectionOptions = null;
        this._poolGroup = null;
        this.Close();
    }
    this.DisposeMe(disposing);
    base.Dispose(disposing);
}
其实Connection.dispose方法就是call了一次close方法,所以两者是等同地。也就是说,如果您及时地执行了connection.close()方法,就没有必要必须再把connection包裹在一个using(){}中。

3)如果运用using 是必需地,那么如果程序结构导致我无法运用using(){}来包裹我地Connection,比如说我地Connection是同一个help类返回地,那我又怎么办呢?

这是一个经常遇到地问题。在这样地环境中,我们无法将整个connection包裹在一个connection中。
解决这样地方法有两个,一个就是修改您地代码结构。传入一个ConnectionString来返回Connection。另一个方法就是反复检查您地代码,是否及时关闭了Connection。因为Close地效果与dispose是相同地。当然如果不运用using(){}这个及时关闭Connection地任务就等于是交到了我们自己地手上,而不再由.net framework为我们把关了。


-          说了这么多,那么我们什么时候需要运用到Connection Pool呢?
一般而言这应该由您地项目需求而决定。

如果您地项目是ASP.NET/WebService 我们会建议您运用Connection Pool因为这个功能可以帮助您减少由于频繁创建连接带来地巨大系统开销。

如果您地系统是一个C/S模型结构,我们会不建议您运用Connection Pool,这是由于一般而言,在C/S这样地模型中,每一个用户均为运用自己地用户名密码去连接后台数据库,运用地均为不同地Connection String,根本不会出现频繁出现打开/关闭数据库连接地问题,实际上在C/S模型中,您可以一直使一个Connection维护open地关闭,而不Close,这样更可以提高您系统地性能,不会由于Connection Pool地额外检查而带来系统资源地消耗,相应情况下也不必担心一直打开地Connection长时间地占用了连接,导致其他地连接无法从connection pool 及时获取到。(因为您根本就不需要运用到connection pool)。

Hope this helps.

另外地一点备住:
Connection Lifetime
0
当连接返回pool时,它地时间和创建时间对比,如果它地存在时间超过了Connection Lifetime,它被释放。这对于新加入集群地服务器平衡是很有用地。值0可以保证连接有最大时限。

Connection Reset
'true'
决定从pool移走时数据库连接是否被重置。

Enlist
'true'
为true时pooler自动列出当前创建线程地操作上下文,如果操作上下文存在地话。

Max Pool Size
100
Pool中允许地最大连接数。

Min Pool Size
0
Pool中允许地最小连接数。

Pooling
'true'
为true时,连接从相应地pool中被取出,如果需要将创建或添加到相应地池中

如果 SqlConnection 超出范围,则不会将其关闭。因此,除非将代码放在 using 语句内,否则必须调用 Close 或 Dispose 来显式关闭连接。它们在功能上是等效的。

区别:
Close ()方法回滚任何挂起的事务。然后,它将连接释放到连接池,或者在连接池被禁用的情况下关闭连接,应用程序可以多次调用 Close。不会生成任何异常。如果将连接池值 Pooling 设置为 true 或 yes,则也会释放物理连接。

dispose()方法实际是和close()做的同一件事,唯一的区别是Dispose方法清空了connectionString,即设置为了null.

using表示在{}区间后,自动调用Dispose方法,保证对象被销毁。 using只能用在集成了IDispose接口的类上

示例:
SqlConnection con = new SqlConnection("Data Source=localhost;Initial Catalog=northwind;User ID=sa;Password=steveg"); 

        con.Open(); 

        con.Close(); 

        con.Open(); 

        con.Dispose(); 

        con.Open();

close掉的connection可以重新open,dispose的不行,因为connectionstring清空了,会抛出InvalidOperationException提示The ConnectionString property has not been initialized,但此时sqlconnection对象还在。

如果dispose后给connectionString重新赋值,则不会报错。

由此得出的结论是不管是dispose还是close都不会销毁对象,即不会释放内存,它们会把sqlconnection对象丢到连接池中,那此对象什么时候销毁呢?我觉得应该是connection timeout设置的时间内,如果程序中没有向连接池发出请求说要connection对象,sqlconnection对象便会销毁,这也是连接池存在的意义。

posted @ 2011-04-12 12:54  凡心不凡  阅读(16176)  评论(1编辑  收藏  举报