使用 Using 語句釋放有限的資源(转)
遇到一個老問題,開始很清楚解決辦法,後來變得不清楚了(因爲我解釋不了該辦法爲什麽是正確的)。相信很多人都遇到使用 SqlDataReader 的時候,出現連接池不足的問題,其根本原因就是打開數據庫連接而沒有關閉,即是 SqlConnection 對象連接的關閉。
有很多人不放心使用 using 語句來關閉而選擇顯式的使用 SqlConnection.Close() 方法來關閉。很有可能是因爲對 using 的不了解,現在帖出MSDN的一些解釋,如下:
第一。SqlConnection 的使用:
原文:http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnection(VS.80).aspx
SqlConnection 对象表示与 SQL Server 数据源的一个唯一的会话。对于客户端/服务器数据库系统,它等效于到服务器的网络连接。SqlConnection 与 SqlDataAdapter和 SqlCommand 一起使用,可以在连接 Microsoft SQL Server 数据库时提高性能。对于所有第三方 SQL 服务器产品以及其他支持 OLE DB 的数据源,请使用OleDbConnection。
当创建 SqlConnection 的实例时,所有属性都设置为它们的初始值。有关这些值的列表,请参见 SqlConnection 构造函数。
如果 SqlConnection 超出范围,则该连接将保持打开状态。因此,必须通过调用 Close 或 Dispose 显式关闭该连接。Close 和 Dispose 在功能上等效。如果连接池值Pooling 设置为 true 或 yes,则基础连接将返回到连接池。另一方面,如果 Pooling 设置为 false 或 no,则实际上会关闭到服务器的基础连接。
若要确保连接始终关闭,请在 using 块内部打开连接,如下面的代码段所示。这样可确保在代码退出代码块时自动关闭连接。
若要部署高性能应用程序,则必须使用连接池。在使用用于 SQL Server 的 .NET Framework 数据提供程序时,不必启用连接池,因为提供程序会自动对此进行管理,不过您可以修改某些设置。有关更多信息,请参见 使用连接池。 |
如果执行 SqlCommand 的方法生成 SqlException,那么当严重级别小于等于 19 时,SqlConnection 将仍保持打开状态。当严重级别大于等于 20 时,服务器通常会关闭 SqlConnection。但是,用户可以重新打开连接并继续操作。
用于创建 SqlConnection 对象实例的应用程序可通过设置声明性或强制性安全要求,要求所有直接和间接的调用方对��码都具有足够的权限。SqlConnection 使用SqlClientPermission 对象设置安全要求。用户可以通过使用 SqlClientPermissionAttribute 对象来验证他们的代码是否具有足够的权限。用户和管理员还可以使用 代码访问安全策略工具 (Caspol.exe) 来修改计算机、用户和企业级别的安全策略。有关更多信息,请参见 .NET Framework 中的安全性。有关演示如何使用安全请求的示例,请参见 代码访问安全性和 ADO.NET。
如果您正在使用 Microsoft .NET Framework 1.0 版,则在使用 Open 连接到 SQL Server 时必须使用 FullTrust 命名权限集。如果使用的是 .NET Framework 1.1 版或更高版本,则此要求不适用。有关更多信息,请参见 请求权限 和 命名的权限集。 |
有关处理来自服务器的警告和信息性消息的更多信息,请参见 使用连接事件。
下面的示例创建一个 SqlCommand 和一个 SqlConnection。SqlConnection 打开,并设置为 SqlCommand 的 Connection。然后,该示例调用 ExecuteNonQuery 并关闭该连接。为了完成此任务,将为 ExecuteNonQuery 传递一个连接字符串和一个查询字符串,后者是一个 Transact-SQL INSERT 语句。
private static void OpenSqlConnection()
{
string connectionString = GetConnectionString();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);
Console.WriteLine("State: {0}", connection.State);
}
}
static private string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=(local);Initial Catalog=AdventureWorks;"
+ "Integrated Security=SSPI;";
}
第二。using 語句的使用
原文:http://msdn.microsoft.com/zh-cn/library/yh598w02(v=VS.80).aspx#1
定义一个范围,将在此范围之外释放一个或多个对象。
C# 通过 .NET Framework 公共语言运行库 (CLR) 自动释放用于存储不再需要的对象的内存。内存的释放具有不确定性;一旦 CLR 决定执行垃圾回收,就会释放内存。但是,通常最好尽快释放诸如文件句柄和网络连接这样的有限资源。
using 语句允许程序员指定使用资源的对象应当何时释放资源。为 using 语句提供的对象必须实现 IDisposable 接口。此接口提供了 Dispose 方法,该方法将释放此对象的资源。
可以在到达 using 语句的末尾时,或者在该语句结束之前引发了异常并且控制权离开语句块时,退出 using 语句。
可以在 using 语句中声明对象(如上所示),或者在 using 语句之前声明对象,如下所示:
可以有多个对象与 using 语句一起使用,但是必须在 using 语句内部声明这些对象,如下所示:
下面的示例显示用户定义类可以如何实现它自己的 Dispose 行为。注意类型必须从 IDisposable 继承。
using System;
class C : IDisposable
{
public void UseLimitedResource()
{
Console.WriteLine("Using limited resource...");
}
void IDisposable.Dispose()
{
Console.WriteLine("Disposing limited resource.");
}
}
class Program
{
static void Main()
{
using (C c = new C())
{
c.UseLimitedResource();
}
Console.WriteLine("Now outside using statement.");
Console.ReadLine();
}
}
第三。總結:
由於using 語句是:Defines a scope, outside of which an object or objects will be disposed. 因此SqlConnection資源被使用後是會調用 disposed 來釋放資源的,當然也會關閉連接,所以以後可以放心使用 using 語句了,呵呵!
另外,在MSDN有人(shiny zhu)做過using語句生成IL代碼的研究 ,如下:
使用using语句实际上生成的IL代码中是一个try, finally代码块,在finally代码块里释放资源。
比如这样一段代码:
using (SqlConnection conn = new SqlConnection())
{
conn.Open();
throw new Exception("Exception!!");//抛出异常之后能回收SqlConnection对象的资源吗?
}
IL代码可为:
// Code size 42 (0x2a)
.maxstack 2
.locals init ([0] class [System.Data]System.Data.SqlClient.SqlConnection conn,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor()
IL_0006: stloc.0
.try
{
IL_0007: nop
IL_0008: ldloc.0
IL_0009: callvirt instance void [System.Data]System.Data.Common.DbConnection::Open()
IL_000e: nop
IL_000f: ldstr "Exception!!"
IL_0014: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_0019: throw
} // end .try
finally
{
IL_001a: ldloc.0
IL_001b: ldnull
IL_001c: ceq
IL_001e: stloc.1
IL_001f: ldloc.1
IL_0020: brtrue.s IL_0029
IL_0022: ldloc.0
IL_0023: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0028: nop
IL_0029: endfinally
} // end handler
可以看到调用了SqlConnection的Dispose方法释放了资源。