大多数数据库接口依赖于某些数据库连接对象,它们好像应用程序代码和数据库之间的桥梁。通常,一个连接必须在执行数据库操作命令之前就要打开。实际上,经常需要一个显示连接来建立和执行命令。在命令执行的整个过程中,该连接必须是打开的,查询的结果将返回一个记录集,才关闭数据库连接。如果正在一个事务中运行,经常会把事务绑定在特定的连接上,当它运行的时候这个连接也必须一直打开,直到这个事务结束才能关闭连接。
在很多环境中,建立连接的开销相当大,这就需要建立一个连接池。在这种情况下,开发者向连接池请求一个连接并在完成以后释放,而无需即时创建和关闭。注意这里不是要你自己去创建连接池,因为现在多数平台都会提供连接池,所以很少需要自己来实现连接池。如果必须自己实现连接池,首先就要检查连接池是不是真的能提高性能(对连接池的创建可以参考后面的代码【1】)。还要注意:越来越多的环境使我们可以更快地创建新的连接,因此也不需要使用缓冲池。
提供连接池的环境把连接池放在一个类似创建新连接的接口后面。用这种方法,无需知道得到得是一个新创建连接还是从连接池里面分配的。类似地,关闭一个连接可能并没有真正关闭它,而只是把它替换为从连接池获取和释放。
无论创建连接的代价是高还是低,连接都必须好好管理,因为它们是珍贵的资源,必须在使用完毕时立刻关闭。还有,如果正在进行一次事务,通常需要保证:在这次特定的事务中,每一个命令都是从同一个连接发出的。
最常见的建议就是用一个到连接池或者连接管理器的调用,显示得到一个连接,并且通过它来执行数据库命令,一旦执行完了,立刻把它关闭。这个建议带来两个问题:首先,保证在任何需要的地方都能得到一个连接;其次,保证不会在最后忘记关闭它(可以参考后面得示例代码【2】)。
现代环境提供了自动的内存管理和垃圾回收机制,因此保证连接关闭的一种方法就是使用垃圾回收器。在这种方式下,连接自身或者引用这个连接的对象会在垃圾回收期间关闭连接。这样做的好处是:它使用了和内存管理相同的机制,同样方便,也不陌生。这样做的问题是:连接的关闭只有当垃圾回收器实际回收内存的时候才发生,可能离这个连接失去它最后一次引用的时间已经很久了,结果是未被引用的连接可能会隔一段时间才被关闭。总的来说,我不喜欢依赖垃圾回收机制,对于其它的机制,甚至是显示关闭都会好一些。当然,垃圾回收机制在其它机制失败的情况下还是一种很好的后备。
连接管理细节描述的往往是数据库交互软件的特征,因此所使用的策略通常是由环境来决定的。
连接池的创建示例代码【1】:
using System;
using System.Timers;
using System.Collections;
using System.Data.SqlClient;
using Common;
namespace SqlDBConnection
{
/// <summary>
/// DBConnection 的数据库连接对象池。
/// </summary>
public sealed class DBConnection:ObjectPool
{
private DBConnection()
{
}
public static readonly DBConnection Instance=new DBConnection();
private static string _connectionstring="数据库连接字符串";
public static string Connectionstring
{
set
{
_connectionstring=value;
}
get
{
return _connectionstring;
}
}
protected override object Create()
{
try
{
SqlConnection temp=new SqlConnection(_connectionstring);
temp.Open();
return(temp);
}
catch
{
return null;
}
}
protected override bool Validate(object o)
{
try
{
SqlConnection temp=(SqlConnection)o;
return(!((temp.State.Equals(System.Data.ConnectionState.Closed))));
}
catch(SqlException)
{
return false;
}
}
protected override void Expire(object o)
{
try
{
((SqlConnection)o).Close();
}
catch(SqlException)
{
}
}
public SqlConnection BorrowDBConnection()
{
try
{
return((SqlConnection)base.GetObjectFromPool());
}
catch(Exception e)
{
throw e;
}
}
public void ReturnDBConnection(SqlConnection c)
{
base.ReturnObjectToPool(c);
}
}
/// <summary>
/// ObjectPool 的对象池。
/// </summary>
public abstract class ObjectPool
{
private long _lastCheckOut;
private static Hashtable locked;
private static Hashtable unlocked;
internal static long CARBAGE_INTERVAL=9*1000;
static ObjectPool()
{
locked=Hashtable.Synchronized(new Hashtable());
unlocked=Hashtable.Synchronized(new Hashtable());
}
internal ObjectPool()
{
_lastCheckOut=DateTime.Now.Ticks;
System.Timers.Timer aTimer=new System.Timers.Timer();
aTimer.Enabled=true;
aTimer.Interval=CARBAGE_INTERVAL;
aTimer.Elapsed+=new System.Timers.ElapsedEventHandler(CollectGarbage);
}
protected abstract object Create();
protected abstract bool Validate(object o);
protected abstract void Expire(object o);
internal object GetObjectFromPool()
{
long now=DateTime.Now.Ticks;
_lastCheckOut=now;
object o=null;
o=Create();
locked.Add(o,now);
return(o);
}
internal void ReturnObjectToPool(object o)
{
if(o!=null)
{
lock(this)
{
locked.Remove(o);
unlocked.Add(o,DateTime.Now.Ticks);
}
}
}
private void CollectGarbage(object sender,System.Timers.ElapsedEventArgs ea)
{
lock(this)
{
object o;
long now=DateTime.Now.Ticks;
IDictionaryEnumerator e=unlocked.GetEnumerator();
try
{
while(e.MoveNext())
{
o=e.Key;
if((now-((long)unlocked[o]))>CARBAGE_INTERVAL)
{
unlocked.Remove(o);
Expire(o);
o=null;
}
}
}
catch(Exception){}
}
}
}
}
数据库连接示例代码【2】:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using SqlDBConnection;
using Common;
namespace MyMedia_Competitor
{
/// <summary>
/// SqlDataBase 的摘要说明。
/// </summary>
public class MySqlDataBase
{
/// <summary>
/// 构造函数
/// </summary>
public MySqlDataBase()
{
}
public DBConnection Connection;
/// <summary>
/// 获取数据库连接接口
/// </summary>
public IDbConnection GetConnection()
{
IDbConnection sqlConnection1 = null;
string connectionstring="数据库连接字符串";
sqlConnection1=(IDbConnection)new SqlConnection(connectionstring);
sqlConnection1.Open();
return sqlConnection1;
}
/// <summary>
/// 将数据库连接接口返回连接池
/// </summary>
public void ReturnConnection(SqlConnection obj)
{
Connection.ReturnDBConnection(obj);
}
/// <summary>
/// 根据数据库类型获取数据库命令接口
/// </summary>
/// <param name="sqlstr">数据库命令字符串</param>
/// <param name="sqlConnection1">数据库连接接口</param>
/// <returns>数据库命令接口</returns>
/// </summary>
private IDbCommand GetCommand(string sqlstr, IDbConnection sqlConnection1)
{
IDbCommand sqlCommand1 = null;
sqlCommand1 = new SqlCommand(sqlstr,(SqlConnection)sqlConnection1);
sqlCommand1.CommandTimeout=99999999;
return sqlCommand1;
}
/// <summary>
/// 根据数据库类型获取数据适配器接口
/// <param name="sqlCommand1">数据库命令接口</param>
/// <returns>数据适配器接口</returns>
private IDataAdapter GetDataAdapter(IDbCommand sqlCommand1)
{
IDataAdapter sqlDataAdapter1 = null;
sqlDataAdapter1 = new SqlDataAdapter((SqlCommand)sqlCommand1);
DataAdapte=sqlDataAdapter1;
return sqlDataAdapter1;
}
/// <summary>
/// 数据适配器属性
/// </summary>
IDataAdapter DataAdapte=null;
private IDataAdapter DataAdapter
{
get
{
return DataAdapte;
}
}
/// <summary>
/// 下面是处理数据,返回结果集
/// </summary>
// 1.
/// <summary>
/// 执行SQL语句并返回受影响的行的数目
/// <param name="sqlstr">数据库命令字符串</param>
/// <returns>受影响的行的数目</returns>
/// </summary>
public int ExecuteNonQuery(string sqlstr)
{
IDbConnection sqlConnection1 = null;
IDbCommand sqlCommand1 = null;
try
{
sqlConnection1 = this.GetConnection();
sqlCommand1 = this.GetCommand(sqlstr, sqlConnection1);
return sqlCommand1.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return 0;
}
finally
{
if (sqlCommand1 != null)
sqlCommand1.Dispose();
if (sqlConnection1 != null)
sqlConnection1.Close();
// Connection.ReturnDBConnection((SqlConnection)sqlConnection1);
}
}
// 2.
/// <summary>
/// 执行SQL语句并返回数据行
/// <param name="sqlstr">数据库命令字符串</param>
/// <returns>数据读取器接口</returns>
/// </summary>
public SqlDataReader ExecuteReader(string sqlstr)
{
IDbConnection sqlConnection1 = null;
IDbCommand sqlCommand1 = null;
try
{
sqlConnection1 = this.GetConnection();
sqlCommand1 = this.GetCommand(sqlstr, sqlConnection1);
return (SqlDataReader)sqlCommand1.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
finally
{
if (sqlCommand1 != null)
sqlCommand1.Dispose();
if (sqlConnection1 != null)
sqlConnection1.Close();
// Connection.ReturnDBConnection((SqlConnection)sqlConnection1);
}
}
// 3.
/// <summary>
/// 执行SQL语句并返回单值对象
/// 即结果集中第一行的第一条数据
/// <param name="sqlstr">数据库命令字符串</param>
/// <returns>单值对象-结果集中第一行的第一条数据</returns>
/// </summary>
public object ExecuteScalar(string sqlstr)
{
IDbConnection sqlConnection1 = null;
IDbCommand sqlCommand1 = null;
try
{
sqlConnection1 = this.GetConnection();
sqlCommand1 = this.GetCommand(sqlstr, sqlConnection1);
return sqlCommand1.ExecuteScalar();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
finally
{
if (sqlCommand1 != null)
sqlCommand1.Dispose();
if (sqlConnection1 != null)
sqlConnection1.Close();
// Connection.ReturnDBConnection((SqlConnection)sqlConnection1);
}
}
// 4.
/// <summary>
/// 填充一个数据集对象并返回之
/// <param name="sqlstr">数据库命令字符串</param>
/// <returns>数据集对象</returns>
/// </summary>
public DataSet GetDataSet(string sqlstr)
{
IDbConnection sqlConnection1 = null;
IDbCommand sqlCommand1 = null;
IDataAdapter sqlDataAdapter1 = null;
DataSet ds = null;
try
{
sqlConnection1 = this.GetConnection();
sqlCommand1 = this.GetCommand(sqlstr, sqlConnection1);
sqlDataAdapter1 = this.GetDataAdapter(sqlCommand1);
ds = new DataSet();
sqlDataAdapter1.Fill(ds);
return ds;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
finally
{
if (sqlCommand1 != null)
sqlCommand1.Dispose();
if (sqlConnection1 != null)
sqlConnection1.Close();
//Connection.ReturnDBConnection((SqlConnection)sqlConnection1);
}
}
// 5.
/// <summary>
/// 执行存储过程
/// <param name="StoredStr">存储过程名</param>
/// <param name="arrParams">所要传入的参数</param>
/// <returns>数据集对象</returns>
/// </summary>
public DataSet GetDataSetForStored(string StoredStr,SqlParameter[] arrParams)
{
IDbConnection sqlConnection1 = null;
IDbCommand sqlCommand1 = null;
IDataAdapter sqlDataAdapter1 = null;
DataSet ds=null;
try
{
sqlConnection1 = this.GetConnection();
sqlCommand1 = this.GetCommand(StoredStr, sqlConnection1);
sqlCommand1.CommandType=CommandType.StoredProcedure;
for(int i=0;i<arrParams.Length;i++)
{
sqlCommand1.Parameters.Add(arrParams[i]);
}
sqlDataAdapter1 = this.GetDataAdapter(sqlCommand1);
ds=new DataSet();
sqlDataAdapter1.Fill(ds);
return ds;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
finally
{
if (sqlCommand1 != null)
sqlCommand1.Dispose();
if (sqlConnection1 != null)
sqlConnection1.Close();
// Connection.ReturnDBConnection((SqlConnection)sqlConnection1);
}
}
// 6.
/// <summary>
/// 执行存储过程
/// <param name="StoredStr">存储过程名</param>
/// <param name="arrParams">所要传入的参数</param>
/// <returns>数据集对象</returns>
/// </summary>
public void RunStored(string StoredStr,SqlParameter[] arrParams)
{
IDbConnection sqlConnection1 = null;
IDbCommand sqlCommand1 = null;
try
{
sqlConnection1 = this.GetConnection();
sqlCommand1 = this.GetCommand(StoredStr, sqlConnection1);
sqlCommand1.CommandType=CommandType.StoredProcedure;
for(int i=0;i<arrParams.Length;i++)
{
sqlCommand1.Parameters.Add(arrParams[i]);
}
sqlCommand1.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
if (sqlCommand1 != null)
sqlCommand1.Dispose();
if (sqlConnection1 != null)
sqlConnection1.Close();
//Connection.ReturnDBConnection((SqlConnection)sqlConnection1);
}
}
/// <summary>
/// 还可以继续扩张
/// </summary>