JAVA 数据库连接池(伪代码,简单易读)

一、引言

      近年来,随着 Internet/Intranet 建网技术的飞速发展和在世界范围内的迅速普及,电子商务的冲击波又一次在世界范围内掀起巨浪,各类商务网站吸引着大量用户的青睐,商务网站的访问量也就越来越大。这种批量、并发性的访问使得商务网站对用户的响应速度会明显变慢,甚至有可能使用户无法登陆网站。不堪重荷的商务网站管理公司,除了提高和优化网站服务器的整体性能外,目标也同时转向程序设计方面,数据库的连接性能优化方面已经成为重点。JAVA 语言的跨平台性、可移植性及安全性等特性,使其应用越来越广泛,尤其在网络应用中更显优势。采用以 JAVA 语言为基础的连接池技术是解决连接数据库瓶颈的一种很好的解决方案。它能够高效地实现数据库连接的管理,从而使系统性能获得显著的改善。

二、传统模式数据连接的分析

      一般情况下,在使用 JAVA 开发基于数据库的 Web 程序时,传统的开发模式基本是按以下步骤:首先在主程序(如 Servlet、Beans)中建立数据库连接;然后进行 SQL 操作,对数据库中的对象进行插入、修改和删除等操作;最后断开数据库连接。

      从图 1 中可以看出,这种开发模式虽然对程序设计和开发者来说比较简单,但也存在很多问题。对于一个简单的数据库应用,由于数据库的访问不是很频繁,只需要在访问数据库时创建一个连接,用完后就关闭它,这样做不会明显地增大系统的开销。但是对于一个复杂的数据库应用,情况就完全不同:

  • 首先,频繁的建立、关闭数据库,会极大的降低系统的性能,增大系统的开销,导致网站的响应速度下降,严重的甚至会造成服务器的崩溃,成为系统的瓶颈。
  • 其次,使用这种传统的模式,还必须管理数据库的每一个连接,以确保他们使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。、
  • 最后,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及地分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

     因此采用运行速度更快、数据库访问效率更高的数据库技术,以提高系统的运行效率将是至关重要的。

三、连接池的解决方案

      上述问题的产生根源是在对连接资源的低效管理,采用数据连接池能够很好地解决此类问题,避免了对于连接的任意、无规则地使用。

      连接池是众多连接对象的“缓冲存储池”,也就是连接对象的集合体,其核心思想是预先建立一些数据库连接的对象并放置于内存中以备使用(图 2)。当程序中需要建立数据库连接时,只需从内存对象(连接池)中取一个来用而不用新建。同样,使用完毕后,只需放回内存即可。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的连接数、每个连接的最大使用次数等等。

      连接池主要由 3 部分组成:连接池的建立、连接池中连接的使用管理、连接池的关闭。具体分析涉及以下方面:

(一)连接池的建立

      应用程序中要建立的其实是一个静态连接池,所谓静态是指连接池中的连接在系统初始化时就已分配好,且不能随意关闭连接。连接池建立时,根据配置,连接池从数据库中一次性获取预设数目的连接对象。这些连接对象作为系统可分配的自由连接,以后所使用的连接都从连接池中获取,这样可避免随意建立、关闭连接所带来的开销。

(二)连接池的分配

      当用户需访问数据库时,不是直接同数据库建立连接,而是向连接池申请一个连接。在这里采用了引用计数的设计方法,该模式在复用资源方面应用得非常广泛,把该方法运用到对于连接的分配和释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现方法是:当用户请求数据库连接时,首先查看连接池中是否有空闲连接。这里的空闲是指连接已经建立但当前未使用。如果存在空闲连接,则把连接分配给用户并作相应处理。主要的处理策略就是设置该连接为已分配状态,即标记该连接
为正在使用,引用计数加 1。如果没有空闲连接,则先查看当前所开的连接数是不是已经达到 maxConn(最大连接数),如果没达到,就给用户重新创建一个连接,并设置其为已分配状态;如果已经达到,就只能按设定的maxWaitTime(最大等待时间)进行等待;如果等待 maxWaitTime 后仍没有空闲连接,就抛出无空闲连接的异常给用户。为了使连接管理服务有更大的通用性,就必须要考虑到多线程环境,即并发问题。在一个多线程的环境下,必须保证连接池管理自身数据的一致性和连接内部数据的一致性,JAVA 自身通过 synchronized 技术提供了对这方面的很好的支持,这样就很容易使线程连接管理成为高效、安全的。

(三)用户等待

      连接池类在达到最大连接数时,用户的请求就要排队等待。当等待超时,递归调用获取连接的方法,尝试再次获取可用连接。

(四)删除策略

      连接对象动态的记录连接次数。如果一个连接的使用次数超过规定值时,就删除该连接。这样做是因为,同一个连接中,每一次连接都会对数据库的数据操作,都会开辟一个内存区域供其使用,当一个连接使用过多,内存叠加区域就会加大,所以使用一定次数后,就要释放资源。另外,当一个连接超过最大空闲时间,就删除该连接,这样做也是为了避免内存资源的浪费。

(五)释放策略

      当用户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就删除该连接,并判断当前连接池内总的连接数是否小于 minConn(最小连接数),若小于就将连接池充满;如果没超过就将该连接标记为开放状态,而不是被关闭,可供再次复用。正是这种策略,保证了数据库连接的有效使用。

(六)连接池的关闭

      当应用程序退出时,应关闭连接池。此时应把在连接池建立时向数据库申请的连接对象统一归还给数据库(即关闭所有数据库连接),这与连接池的建立正好是一个相反过程。

(七)连接池的配置

      数据库连接池到底要放置多少个连接,才能使系统的性能更佳,这是个配置策略。这里用 minConn 和maxConn 来限制。minConn 是当应用启动的时候连接池所创建的连接数,如果过大,启动将变慢,但是启动后响应更快;如果过小,启动加快,但是最初使用的用户将因为连接池中没有足够的连接而不可避免的延缓了执行速度。配置策略是:根据具体的应用需求,给出一个初始的连接池连接数目以及一个连接池可以承受的最大连接数目。连接池管理策略是连接池管理机制的核心。尤其是连接池的分配与释放,在实际应用中是对性能有很大影响的一个因素。合理的分配与释放,可以提高连接的复用度,避免频繁地建立、释放连接所带来的系统资源开销,同时还可以让用户访问的速度加快。

四、连接池的具体实现

      首先,在建立连接池之前,我们要确定数据库的一些基本属性,如 URL,username,password 等。我们可以先把这些属性放置在一个文件(文件名为 PropFile)中,然后,设计一个 GetProperty 类,该类的功能是从文件PropFile 中读取数据库的一些属性值。这样做的好处是,连接池不用关心操作的是什么类型的数据库,以及数据库的属性。当数据库的类型或属性发生改变时,我们只要修改文件 PropFile 即可。GetProperty 类中最重要的函数是构造函数,该函数的主要功能是从文件 PropFile 中读取数据库的属性值。其核心代码如下:

    public GetProperty(String infile){
        InputStream = InStream.getClass();
        getResourceAsStream(infile);
        Properties Props = new Properties;
        try {
            Props.load(InStream);
            driver = Props.getProperty("driver");
            url = Props.getProperty("url");
            username = Props.getProperty("username");
            password = Props.getProperty("password");
        }catch(Exception e) {// 输出出错信息 return;
        }
    }

      现在可以开始建立连接池了,连接池必须提供几个最基本的接口,下面我们以伪代码的形式给出这几个接口的定义。

    public class ConnectionPool {
        private Connection CreateConn() {
        // 创建新的连接
        // 首先检查有无空闲连接,如果没有,再检查连接是否达到了上限,
        // 如果连接数没有达到上限,则创建新的连接。
        }
        public synchronized Connection getConnection() {
        // 把用户释放的连接放入连接池中
        }
        public synchronized void release() {
        // 关闭所有连接
        }
    }

      连接池建立好之后,还要建立一个管理类(ConnectionPoolManager)来管理连接池,我们仍然以伪代码的形式给出这个类的定义。

    public class ConnectionPoolManager {
        private void init() {
        // 管理类的初始化
        }
        public Connection getConnection(String poolname) {
        // 从指定的连接池中取得一个数据库连接
        }
        public void backconn(String poolname, Connection conn) {
        // 把用户释放的连接归还给指定的连接池
        }
        public synchronized void close {
        // 关闭一个连接池
        }
        public synchronized void release() {
        // 释放所有的连接
        }
        public synchronized void destroy() {
        // 销毁一个连接池
        }
    }

      对于大型的、复杂的、网络化的数据库应用系统而言,恰当的使用连接池技术,可以大大地提高程序的执行效率。

五、结束语

      总之,由于 JAVA 有着其它语言不可比拟的优点,JAVA 的应用将越来越广泛,笔者着重阐述了 JAVA数据库应用中连接池的基本工作机制,并实现了一个基本的连接池,对开发高性能的数据库应用程序有一定的实用和参考价值。

摘自:尚 弘
[ 参考文献]
[1 ] 普悠玛数位科技有限公司. JAVA2 程序设计. 北京:清华大学出版社,2002
[2 ] 光军、胡波.JSP 应用开发实例详解. 北京:北京航天航空大学出版社,2002
[3] [美]Joe Zuffoletto.BEA weblogic server bible. 北京:电子工业出版社,2003
[4] 李世祥. Structs 框架应用与开发. 大连:东软电子出版社,2007

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。