java数据库连接池技术原理(浅析)

在执行数据库 SQL 语句时,我们先要进行数据连接;而每次创建新的数据库的连接要消耗大量的资源,这样,大家就想出了数据库连接池技术。它的原理是,在运行过程中,同时打开着一定数量的数据库连接,形成数据连接池,当需要用到数据连接时,就从中取出一个连接,完成某些 SQL 操作后,系统自动回收,以供其它用户(或进程)调用。

我们知道,java 标准的 java.sql.Connection 表示一个数据连接。我们封装了这个类,形成自己的数据库连接池。为了说明方便,这里用实际的类来显示:

DBConnectionPool   真正的数据连接池

DBConnectionManager   对多个池进行管理

实际执行过程

1)          新建一个 DBConnectionManager 类的实例。

2)          然后调用 DBConnectionManager. CreatePool() 创建一个连接池,并把这个连接池加入到 pools 的 HasthTable 中。(这种过程可执行多次,对应不同的数据连接,可能是 sql2k 的,也可能是 oracle 的,但生成的 DBConnectionPool 都要放到 pools 中进行统一管理,用并用一个名字与相应的 DBConnectionPool 对应起来)。

3)          当需要数据连接时,首先得到一个 DBConnectionPool,然后从 DBConnectionPool 中看有没有空闲的连接,如果有,则使用。如果没有,显没过最大连接数,则创建一个 Connection 连接,并返回这上连接。

4)          如果某个连接使用完毕,则调用 DBConnectionManager.freeConnection(String name, Connection con),它又调用 DBConnectionPool. freeConnection(Connection con),此时,连接并不真正释放,而是把这个暂时不用的 Connection 放到 DBConnectionPool 的 freeConnections 数组中 ( 同时,通知其它正在等待连接的线程。这样,以后要用时,就不用再新建 Connection。

浅析(二)

一般情况下,在使用开发基于数据库的 WEB 程序时,传统的模式基本是按以下步骤:

   1. 在主程序(如 Servlet、Beans)中建立数据库连接。

   2. 进行 SQL 操作,取出数据。

   3. 断开数据库连接。

  使用这种模式开发,存在很多问题。首先,我们要为每一次 WEB 请求(例如察看某一篇文章的内容)建立一次数据库连接,对于一次或几次操作来讲,或许你觉察不到系统的开销,但是,对于 WEB 程序来讲,即使在某一较短的时间段内,其操作请求数也远远不是一两次,而是数十上百次(想想全世界的网友都有可能在您的网页上查找资料),在这种情况下,系统开销是相当大的。事实上,在一个基于数据库的 WEB 系统中,建立数据库连接的操作将是系统中代价最大的操作之一。很多时候,可能您的网站速度瓶颈就在于此。

  其次,使用传统的模式,你必须去管理每一个连接,确保他们能被正确关闭,如果出现程序异常而导致某些连接未能关闭,将导致数据库系统中的内存泄露,最终我们将不得不重启数据库。

  针对以上问题,我们首先想到可以采用一个全局的 Connection 对象,创建后就不关闭,以后程序一直使用它,这样就不存在每次创建、关闭连接的问题了。但是,同一个连接使用次数过多,将会导致连接的不稳定,进而会导致 WEB SERVER 的频频重启。故而,这种方法也不可取。实际上,我们可以使用连接池技术来解决上述问题。首先,介绍一下连接池技术的基本原理。顾名思义,连接池最基本的思想就是预先建立一些连接放置于内存对象中以备使用:

  如图所示,当程序中需要建立数据库连接时,只须从内存中取一个来用而不用新建。同样,使用完毕后,只需放回内存即可。而连接的建立、断开都有连接池自身来管理。同时,我们还可以通过设置连接池的参数来控制连接池中的连接数、每个连接的最大使用次数等等。通过使用连接池,将大大提高程序效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。下面我们以一个名为 ConnectionPool 的连接池为例来看看连接池的实现。先看看 ConnectionPool 的基本属性:

   m_ConnectionPoolSize:连接池中连接数量下限

   m_ConnectionPoolMax:连接池中连接数量上限

   m_ConnectionUseCount:一个连接的最大使用次数

   m_ConnectionTimeout:一个连接的最长空闲时间

   m_MaxConnections = -1:同一时间的最大连接数

   m_timer:定时器

  这些属性定义了连接池与其中的每个连接的有效状态值。连接池的自我管理,实际上就是通过定时的对每个连接的状态、连接的数量进行判断而进行相应操作。其管理流程如下:

通过上图,我们可以定义出 ConnectionPool 要完成管理所需要的基本接口:

public class ConnectionPool implements TimerListener{

   public boolean initialize() // 连接池初始化

   public void destroy() // 连接池的销毁

   public synchronized java.sql.Connection getConnection() // 取一个连接

   public synchronized void close() // 关闭一个连接

   private synchronized void removeFromPool() // 把一个连接从连接池中删除

   private synchronized void fillPool() // 维护连接池大小

   public synchronized void TimerEvent() // 定时器事件处理函数

}

  通过这几个接口,已经可以完成连接池的基本管理。在 TimeEvent()函数中完成连接池的状态检验工作,fillPool() 时连接池至少保持最小连接数。因为我们要保存每一个连接的状态,所以还需要一个数据库连接对象:

class ConnectionObject{

   public java.sql.Connection con; public boolean inUse; // 是否被使用标志

   public long lastAccess; // 最近一次开始使用时间

   public int useCount; // 被使用次数

}

加入了 ConnectionObject 对象后,在 ConnectionPool 中操作的应该只是 ConnectionObject, 而其他进程需要的只是 ConnectionObject 的 con 属性,因此我们再加入一个类,作为其他进程获得与返回连接的接口: CLASS Conn{

   GetConnection(); // 从连接池中取出一个有效连接

   CloseConnection(); // 返回连接,此时并没有关闭连接,只是放回了连接池

   DestroyPool(); // 销毁连接池

}

   最后我们的整个系统总的架构如下:

  通过上面的介绍,我们可以看出,连接池技术的关键就是其自身的管理机制,以上的管理流程只是本人一点见解,关键是想向大家介绍一种思路,在此基础上,您可以进一步完善连接池技术为您所用。