实现高效的数据库连接池(附带完整代码C#和Java实现),数据库相关文章,Access,数...

来源:百度文库 编辑:神马文学网 时间:2024/04/18 15:57:31
据库应用程序程序员
系统分析员
模块设计师
有一定功底的程序员
目录引言
数据库连接池(Connection Pool)的工作原理
连接池关键问题分析
并发问题
事务处理
连接池的分配与释放
连接池的配置与维护 关键议题 引用记数 如何实现事务处理
 管理连接池
结合代码说明 构造方法 启动服务StartService 停止服务StopService 申请 GetConnectionFormPool 释放DisposeConnection 如何更新属性 如何确定连接是否失效 使用线程管理连接池 threadCreate threadCheck 其他
--------------------------------------------------------------------------------引言一般的数据库应用程序大致都遵循下面的步骤:初始化程序
用户在UI上输入操作
由用户操作产生数据库操作
将数据库操作递交到数据库服务器
.... (重复2~4)
关闭应用程序
  而本文则着重讲解上面第4步骤.在着一步骤中我们经常是,打开数据库连接操作数据库,最后关闭数据库.
  在服务器端程序设计上与数据库的操作显得十分重要,因为你要处理的数据操作十分巨大.如果频繁创建数据库连接频繁关闭数据库连接则会引起效率低下甚至引发程序崩溃.
  也许我们可以有另一种操作数据库的形式,我们可以在程序运行时打开一个数据库连接,让这个连接永久存在直到程序'死亡',那么这样做也有不安全隐患,我们知道一个对象存在时间越长或被使用次数越多则它表现的越不稳定,着不稳定因素是由于对象内部可能存在的潜在设计问题产生,对于数据库连接对象道理也一样.我们不能保证一个Connection对象里面能一点问题不存在.所以我们也不敢长时间将它长时间占用内存.
  既然有这么多的问题由此我们需要一个能帮我们维护数据库连接的东西-它就是连接池,网上有很多的连接池例子,但是多数都是简单的例子,或者介绍比较复杂的连接池原理,没有一个比较完整介绍和实现连接池的例子.这里就介绍你如何自己制作一个连接池.
  对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决我们的问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。连接池的基本工作原理见下图。数据库连接池(Connection Pool)的工作原理 
 连接池关键问题分析  1、并发问题  为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为各个语言自身提供了对并发管理的支持像java,c#等等,使用synchronized(java)lock(C#)关键字即可确保线程是同步的。使用方法可以参考,相关文献。  2、事务处理  我们知道,事务具有原子性,此时要求对数据库的操作符合“ALL-ALL-NOTHING”原则,即对于一组SQL语句要么全做,要么全不做。
  我们知道当2个线程公用一个连接Connection对象,而且各自都有自己的事务要处理时候,对于连接池是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定那个数据库操作是对应那个事务的,这是由于我们有2个线程都在进行事务操作而引起的。为此我们可以使用每一个事务独占一个连接来实现,虽然这种方法有点浪费连接池资源但是可以大大降低事务管理的复杂性。  3、连接池的分配与释放  连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。
  对于连接的管理可使用一个List。即把已经创建的连接都放入List中去统一管理。每当用户请求一个连接时,系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他(如何能找到最合适的连接文章将在关键议题中指出);如果没有就抛出一个异常给用户,List中连接是否可以被分配由一个线程来专门管理捎后我会介绍这个线程的具体实现。    4、连接池的配置与维护  连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConnection)和最大连接数(maxConnection)等参数来控制连接池中的连接。比方说,最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过软件需求上得到。
  如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。 关键议题
引用记数
  在分配、释放策略对于有效复用连接非常重要,我们采用的方法也是采用了一个很有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面用的非常广泛,我们把该方法运用到对于连接的分配释放上。每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现上,我们对Connection类进行进一步包装来实现引用记数。被包装的Connection类我们提供2个方法来实现引用记数的操作,一个是Repeat(被分配出去)Remove(被释放回来);然后利用RepeatNow属性来确定当前被引用多少,具体是哪个用户引用了该连接将在连接池中登记;最后提供IsRepeat属性来确定该连接是否可以使用引用记数技术。一旦一个连接被分配出去,那么就会对该连接的申请者进行登记,并且增加引用记数,当被释放回来时候就删除他已经登记的信息,同时减少一次引用记数。  这样做有一个很大的好处,使得我们可以高效的使用连接,因为一旦所有连接都被分配出去,我们就可以根据相应的策略从使用池中挑选出一个已经正在使用的连接用来复用,而不是随意拿出一个连接去复用。策略可以根据需要去选择,我们有4策略可是使用:1.ConnLevel_ReadOnly 独占方式
  使用空闲的实际连接分配连接资源,并且在该资源释放回之前,该资源在连接池中将不能将其引用分配给其他申请者。如果连接池中所有实际连接资源都已经分配出去,那么即使连接池可以在分配引用资源在该模式下连接迟将不会分配连接资源,连接池会产生一个异常,标志连接池资源耗尽。
  例:假如一个实际连接可以被分配5次,那么使用该模式申请连接的话您将损失4个可分配的连接,只将得到一个连接资源。 直至该资源被释放回连接池,连接池才继续分配它剩余的4次机会。
  当你在使用连接时可能应用到事务时,可以使用该模式的连接,以确定在事务进行期间您可以对该连接具有独享权限,以避免各个数据库操作访问的干扰。
2.ConnLevel_High 优先级-高
  使用空闲的实际连接分配连接资源,并且在该资源释放回之前,该资源在连接池中将可能将其引用分配给其他申请者。*注意:此级别不保证在分配该资源后,仍然保持独立占有连接资源,若想独立占有资源请使用ReadOnely, 因为当连接池达到某一时机时该资源将被重复分配(引用记数)然而这个时机是不可预测的。如果您申请的连接会用于事务处理您可以使用ConnLevel_ReadOnly级别。
3.ConnLevel_None 优先级-中
  适当应用引用记数技术分配连接资源。
在该模式下,连接池内部会按照实际连接已经使用次数排序(多->少),然后在结果中选取 1/3 位置的连接资源返回。与优先级-高相同该模式也不具备保持独立占有连接资源的特性。如果您申请的连接会用于事务处理您可以使用ConnLevel_ReadOnly级别。
4.ConnLevel_Bottom 优先级-底
尽可能使用引用记数技术分配连接。在该模式下,连接池内部会按照实际连接已经使用次数排序(多->少),然后在结果中选取被使用最多的返回。该模式适合处理较为不重要的连接资源请求。与优先级-高相同该模式也不具备保持独立占有连接资源的特性。如果您申请的连接会用于事务处理您可以使用ConnLevel_ReadOnly级别。以上4条策略选自datebasepool_SDK(datebasepool是本文所开发的最终产物)
如何实现事务处理
   前面谈到的都是关于使用数据库连接进行普通的数据库访问。对于事务处理,情况就变得比较复杂。因为事务本身要求原子性的保证,此时就要求对于数据库的操作符合"All-All-Nothing"原则,即要么全部完成,要么什么都不做。如果简单的文章出处:DIY部落(http://www.diybl.com/course/7_databases/database_other/2008921/144191.html)