C#数据库连接池
来源:互联网 发布:java的成绩管理系统 编辑:程序博客网 时间:2024/06/13 10:43
使用C#数据库连接池
连接到数据库服务器通常由几个需要软长时间的步骤组成。必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次连接,必须分析连接字符串信息,必须由服务器对连接进行身份验证,等等。
实际上,大部份的应用程序都是使用一个或几个不同的连接配置。当应用程序的数据量和访问量大的时候,这意味着在运行应用程序的过程中,许多相同的连接将反复地被打开和关闭,从而会引起数据库服务器效率低下甚至引发程序崩溃。为了确保应用程序的稳定和降低性能成本,我们可以在ADO.NET中使用称为连接池的优化方法来管理维护连接。
C#数据库连接池可以减少创建连接的次数。定义最小连接数(固定连接数),当用户在连接上调用Open,连接池就会检查池中是否有可用的连接。如果发现有连接可用,会将该连接返回给调用者,而不是创建新连接。应用程序在该连接上调用Close时,连接池会判断该连接是否在最小连接数之内,如果“是”会将连接回收到活动连接池中而不是真正关闭连接,否则将烧毁连接。连接返回到池中之后,即可在下一个Open调用中重复使用。
创建C#数据库连接池
以下示例使用C#连接SQL数据库:
- class DbConn
- {
- //usingSystem.Data;
- //usingSystem.Data.SqlClient;
- private const int MaxPool=10;//最大连接数
- private const int MinPool=5;//最小连接数
- private const bool Asyn_Process=true;//设置异步访问数据库
- //在单个连接上得到和管理多个、仅向前引用和只读的结果集(ADO.NET2.0)
- private const bool Mars=true;
- private const int Conn_Timeout=15;//设置连接等待时间
- private const int Conn_Lifetime=15;//设置连接的生命周期
- private string ConnString="";//连接字符串
- private SqlConnection SqlDrConn=null;//连接对象
- public DbConn()//构造函数
- {
- ConnString=GetConnString();
- SqlDrConn=new SqlConnection(ConnString);
- }
- private string GetConnString()
- {
- return"server=localhost;"
- +"integratedsecurity=sspi;"
- +"database=pubs;"
- +"MaxPoolSize="+MaxPool+";"
- +"MinPoolSize="+MinPool+";"
- +"ConnectTimeout="+Conn_Timeout+";"
- +"ConnectionLifetime="+Conn_Lifetime+";"
- +"AsynchronousProcessing="+Asyn_Process+";";
- //+"MultipleActiveResultSets
="+Mars+";"; - }
- public DataTable GetDataReader(string StrSql)//数据查询
- {
- //当连接处于打开状态时关闭,然后再打开,避免有时候数据不能及时更新
- if(SqlDrConn.State==ConnectionState.Open)
- {
- SqlDrConn.Close();
- }
- try
- {
- SqlDrConn.Open();
- SqlCommandSql Cmd=new SqlCommand(StrSql,SqlDrConn);
- SqlDataReader SqlDr=SqlCmd.ExecuteReader();
- if(SqlDr.HasRows)
- {
- DataTable dt=new DataTable();
- //读取SqlDataReader里的内容
- dt.Load(SqlDr);
- //关闭对象和连接
- SqlDr.Close();
- SqlDrConn.Close();
- returndt;
- }
- returnnull;
- }
- catch(Exception ex)
- {
- System.Windows.Forms.MessageBox.Show(ex.Message);
- return null;
- }
- finally
- {
- SqlDrConn.Close();
- }
- }
- }
通过调用SqlDrConn.Open()方法打开连接,这时候连接池就会初始化并建立设定的最小连接数。想更清楚了解到连接池的状况可以通过SQL的查询分析器执行存储过程sp_Who,它会列出当前的数据库进程,查看loginname、dbname可以区分用户的连接信息,但要注意的是登录查询分析器本身会使用两个连接,所以最好用另一个用户名登录查询分析器。使用此方法还有一个麻烦地方就是要经常按“执行查询”以更新进程信息。还有另一种方法个人认为较好的,通过控制面板→管理工具→性能,右击添加计算器,性能对象选择SQlServer:GeneralStatistics(常规统计)然后计算器选择UserConnections(用户连接)最后按“添加”就可以实时查看当前连接数。
到了这里,连接池已经实现了,但问题往往会出现在运行过程中。如连接池的连接数满了该怎样处理?在这里我们应该合理设置连接字符串中的ConnectTimeout属性和ConnectionLifetime属性(上面有解释)延长等待时间,尽可能地在每次使用完连接之后调用Close方法关闭连接。但从中也有没法避免的,当连接数满了并且申请连接的时间超过设置连接等待的时间时,程序将会引发InvalidOperationExceptio
使用方法:在连接字符串中加上AsynchronousProcessing=true表示使用异步处理操作。
当应用程序不再需要用到连接池的时候可以使用ClearPool或ClearAllPools方法清空连接池也可作重置连接池使用,方法如下:
SqlConnection.ClearPool(SqlConnection connection)清空关联的连接池
SqlConnection.ClearAllPools()清空所有连接池
调用上述方法,如果连接正在使用,连接池会做相应标记,等连接关闭时自动烧毁。
小结C#数据库连接池
优点:当数据库操作和访问频繁的时候,减少创建连接和打开连接所耗的时间,提升数据库服务器的性能。
缺点:数据库连接池中可能存在着多个没有被使用的连接一直连接着数据库,这意味着资源的浪费。
在企业级软件开发过程中,为了改善应用程序的性能需要通常使用对象池来控制对象的实例化。例如,在我们每次需要连接一个数据库时都需要创建一个数据库连接,而数据库连接是非常昂贵的对象。所以,为了节省为每次数据库调用都实例化一个数据库连接的资源,我们可以缓存并重用一些创建好的数据库连接对象并通过节省为每次数据库调用都创建一个数据库连接对象的时间和资源来大幅度提高程序性能。
实现对象池
图 5
ObjectPool 类
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Collections;using System.Timers;namespace ObjectPoolSample{ public abstract class ObjectPool { //Last Checkout time of any object from the pool. private long lastCheckOut; //Hashtable of the check-out objects. private static Hashtable locked; //Hashtable of available objects private static Hashtable unlocked; //Clean-Up interval internal static long GARBAGE_INTERVAL = 90 * 1000; //90 seconds static ObjectPool() { locked = Hashtable.Synchronized(new Hashtable()); unlocked = Hashtable.Synchronized(new Hashtable()); } internal ObjectPool() { lastCheckOut = DateTime.Now.Ticks; //Create a Time to track the expired objects for cleanup. Timer aTimer = new Timer(); aTimer.Enabled = true; aTimer.Interval = GARBAGE_INTERVAL; aTimer.Elapsed += new 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; lock (this) { try { foreach (DictionaryEntry myEntry in unlocked) { o = myEntry.Key; unlocked.Remove(o); if (Validate(o)) { locked.Add(o, now); return o; } else { Expire(o); o = null; } } } catch (Exception) { } 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, 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]) > GARBAGE_INTERVAL) { unlocked.Remove(o); Expire(o); o = null; } } } catch (Exception) { } } } }}
DBConnectionSingleton 类
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data.SqlClient;using System.Data;namespace ObjectPoolSample{ public sealed class DBConnectionSingletion : ObjectPool { private DBConnectionSingletion() { } public static readonly DBConnectionSingletion Instance = new DBConnectionSingletion(); private static string connectionString = @"server=(local);Trusted Connection=yes;database=northwind"; public static string ConnectionString { get { return connectionString; } set { connectionString = value; } } protected override object Create() { SqlConnection conn = new SqlConnection(connectionString); conn.Open(); return conn; } protected override bool Validate(object o) { try { SqlConnection conn = (SqlConnection)o; return !conn.State.Equals(ConnectionState.Closed); } catch (SqlException) { return false; } } protected override void Expire(object o) { try { SqlConnection conn = (SqlConnection)o; conn.Close(); } catch (SqlException) { } } public SqlConnection BorrowDBConnection() { try { return (SqlConnection)base.GetObjectFromPool(); } catch (Exception e) { throw e; } } public void ReturnDBConnection(SqlConnection conn) { base.ReturnObjectToPool(conn); } }}
为什么要使用单例模式?
使用数据库连接池
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Configuration;using System.Data.SqlClient;namespace ObjectPoolSample{ class Program { static void Main(string[] args) { //Initialize the Pool DBConnectionSingletion pool = DBConnectionSingletion.Instance; //Set the ConnectionString of the DatabaseConnectionPool ConnectionStringSettingssettings = ConfigurationManager.ConnectionStrings["NorthwindConnectionStrin g" ]; DBConnectionSingletion.ConnectionString = settings.ConnectionString; //Borrow the SqlConnection object from the pool SqlConnection conn = pool.BorrowDBConnection(); //Return the Connection to the pool after using it pool.ReturnDBConnection(conn); Console.ReadLine(); } }}
总结
在企业级计算的多线程世界中同步是一个极其重要的概念。它被广泛用于数据库,消息队列以及Web 服务器等闻名应用上。任何开发多线程应用程序的开发人员都必须对他们的同步概念特别清楚。不是为了让每个对象都是线程安全的而导致系统不堪重负,而是应该关注死锁情况并在程序设计之初就解决尽可能多的死锁问题。理解同步带来的性能瓶颈问题同样很重要,因为它将影响应用程序的总体性能。在这一章,除了探讨.NET Framework 中自带的同步特性,我们也开发了两个有用的应用程序:
- C#数据库连接池
- C#数据库连接池详解
- C# 数据库连接池
- 使用c#数据库连接池
- c#数据库连接池使用
- C#数据库连接池
- C# 数据库连接池
- 详细分析C#数据库连接池
- C#数据库连接池详细分析
- C#数据库连接
- c#数据库连接
- C#数据库连接
- c# 数据库连接
- C# 数据库连接
- C# 数据库连接
- C# 数据库连接
- C# 数据库连接
- c#数据库连接
- Mybatis学习(二)
- Python调用不在同一个文件夹下的Python程序,并且如何解决pyinstaller打包路径问题
- Android Studio3.0 中在引入Greendao3.2的时候编译通过不了解决办法
- javassist生成的对象回收
- 谈谈Mysql之修改表引擎
- C#数据库连接池
- JAVA 字符串编码总结
- 唯一可译码判决准则
- HTTPS学习笔记
- 思科PIX防火墙配置清除
- 将Eclipse代码Import AndroidStudio 后出现的一些问题解决
- taglib指令作用以及属性
- perf-tools
- JVM ClassLoader类加载原理