日期:2014-05-16  浏览次数:20448 次

数据库连接池技术的研究与实现
数据库连接池技术,它的原理是,在应用系统运行过程中,同时打开着一定数量的数据库连接,形成数据连接池,需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去,完成某些SQL操作后,系统自动回收,以供其它用户(或进程)调用。现在大多数的WEB应用服务器如BEA的WebLogic和IBM的WebSphere等提供了连接池的机制.不过,比起配置应用服务器提供的数据库连接池,自己写一个数据库连接池更有成就感.

要自己动手写一个连接池,有许多功能上的考虑。
1)连接池的分配与释放
连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。
  对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接按创建时间存放到一个空闲池中。每当用户请求一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxConn),如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout,则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法。
2)连接池的配置与维护
连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConn)和最大连接数(maxConn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过反复测试,找到最佳点。
3)并发问题
  为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为Java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如:
  public synchronized Connection getConnection()



一个ConnectionPool的实现
以下代码在jdk1.4以上版本编译通过
package test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Vector;

public class ConnectionPool {
 private final Vector pools = new Vector();

 private int clients;

 private final int maxClients=25;

 /**
  * 获取数据库连接 如果当前池中有可用连接,则将池中最后一个返回;若没有,则创建一个新的返回
  */
 public synchronized java.sql.Connection getConnection() {
  java.sql.Connection con = null;
  if (pools.size() > 0) {
   // Pick the first Connection in the Vector
   // to get round-robin usage
   con = (java.sql.Connection) pools.firstElement();
   pools.removeElementAt(0);
   try {
    if (con.isClosed()) {
     System.out
       .println("Removed bad connection from connection pool");
     // Try again recursively
     con = getConnection();
    }
   } catch (SQLException e) {
    System.out
      .println("Removed bad connection from  connection pool");
    // Try again recursively
    con = getConnection();
   }
  } else if (maxClients == 0 || clients < maxClients) {
   con = createConnection();
  }
  if (con != null) {
   clients++;
  }
  return con;
 }

 /*
  * 当对一个连接的请求不能被满足时,等待,直到pool中有空闲Connection
  */
 public synchronized java.sql.Connection getConnection(long timeout) {
  long startTime = new Date().getTime();
  java.sql.Connection con;
  while ((con = getConnection()) == null) {
   try {
    wait(timeout);
   } catch (InterruptedException e) {
   }
   if ((new Date().getTime() - startTime) >= timeout) {
    // Timeout has expired
    return null;
   }
  }
  return con;
 }

 /*
  * 生成一个数据库连接conn
  */
 public static Connection createConnection() {
  Connection conn = null;
  try {
   Class.forName("org.gjt.mm.mysql.Driver").newInstance();
   String url = "jdbc:mysql://localhost:3306/microerp";
   String user = "root";
   String password = "";
   conn = DriverManager.getConnection(url, user, password);
  } catch (InstantiationException e) {
   // TODO自动生成 catch 块
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO自动生成 catch 块
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   // TODO自动生成 catch 块
   e.printStackTrace();
  } catch (SQLException e) {
   // TODO自动生成 catch 块
   e.printStackTrace();
  }
  return conn;
 }

 /**
  * 将使用完毕的数据库连接放回池中 若池中连接已经超过阈值,则关闭该连接;否则放回池中下次再使用
  */
 public synchronized void releaseConnection(Connection conn) {
  if (pools.size() >= maxClients)
   try {
    conn.close();
   } catch (SQLException e) {
    // TODO自动生成 catch 块
    e.printStackTrace();
   }
  else {
   pools.add(conn);
   clients--;
   notify();
  }
 }
 
 public synchronized void clear(){