关于连接池的笔记

最近因各种各样的原因.都要用上DBConnectionManager连接池.

可惜的是找了整个互联网都找不到一个可以通过的例子.

以下是完整的可调用与可使用的例子.

文件序列如下

DBConnectionManager.java

dbop.java

db.properties

test.jsp

test2.jsp

以下为DBConnectionManager.java 源码

package com.china3cts;
import java.sql.*;
import java.io.*;
import java.util.*;
public class DBConnectionManager {

  private static int clients = 0;
  private static DBConnectionManager instance;
  private Vector drivers = new Vector();
  private PrintWriter log;
  private Hashtable pools = new Hashtable();


  public DBConnectionManager() {
    init();
  }
  private void log(String msg) {
    log.println(new java.util.Date() + ": " + msg);
  }

  /**
  * 将文本信息与异常写入日志文件
  */
  private void log(Throwable e, String msg) {
    log.println(new java.util.Date() + ": " + msg);
    e.printStackTrace(log);
  }

  public static synchronized  DBConnectionManager getInstance() {
    if (instance == null) {
      instance = new DBConnectionManager();
    }
    clients++;
    return instance;
  }
  private void init() {
    InputStream is = getClass().getResourceAsStream("db.properties");
    Properties dbProps = new Properties();
    try {
      dbProps.load(is);
    }
    catch (Exception e) {
        System.err.println("Can not read the properties file. " +
        "Make sure db.properties is in the CLASSPATH");
        return;
    }
 
    loadDrivers(dbProps);
    createPools(dbProps);
  }
  public void freeConnection(String name, Connection con) {
    DBConnectionPool pool = (DBConnectionPool) pools.get(name);
    if (pool != null) {
      pool.freeConnection(con);
    }
  }
  public Connection getConnection(String name) {
    DBConnectionPool pool = (DBConnectionPool) pools.get(name);
    if (pool != null) {
      return pool.getConnection();
    }
    return null;
  }
  public Connection getConnection(String name, long time) {
    DBConnectionPool pool = (DBConnectionPool) pools.get(name);
    if (pool != null) {
      return pool.getConnection(time);
    }
    return null;
  }
  public synchronized void release() {
    // 等待直到最后一个客户程序调用
    if (--clients != 0)
    {
      return;
    }
    Enumeration allPools = pools.elements();
    while (allPools.hasMoreElements())
    {
      DBConnectionPool pool = (DBConnectionPool)allPools.nextElement();
      pool.release();
    }
    Enumeration allDrivers = drivers.elements();
    while (allDrivers.hasMoreElements())
    {
      Driver driver = (Driver) allDrivers.nextElement();
      try {
        DriverManager.deregisterDriver(driver);
        log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册");
      }
      catch (SQLException e) {
      log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
      }
    }
  }


/*
drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver

logfile=D://user//src//java//DBConnectionManager//log.txt

idb.url=jdbc:idb:c://local//javawebserver1.1//db//db.prp

idb.maxconn=2

access.url=jdbc:odbc:demo

access.user=demo

access.password=demopw

*/

  private void loadDrivers(Properties props) {
    String driverClasses = props.getProperty("drivers");
    StringTokenizer st = new StringTokenizer(driverClasses);
    while (st.hasMoreElements()) {
      String driverClassName = st.nextToken().trim();
      try {
        Driver driver = (Driver)
          Class.forName(driverClassName).newInstance();
        DriverManager.registerDriver(driver);
        drivers.addElement(driver);
        //System.err.println("Registered JDBC driver " + driverClassName);
      }
      catch (Exception e) {
        System.err.println("Can not register JDBC driver: " + driverClassName + ", Exception: " + e.toString());
      }
    }
  }
  private void createPools(Properties props) {
    Enumeration propNames = props.propertyNames();
    while (propNames.hasMoreElements())
    {
      String name = (String) propNames.nextElement();
      if (name.endsWith(".url"))
      {
        String poolName = name.substring(0, name.lastIndexOf("."));
        String url = props.getProperty(poolName + ".url");
        if (url == null) {
          System.err.println("No URL specified for " + poolName);
          continue;
        }
        String user = props.getProperty(poolName + ".user");
        String password = props.getProperty(poolName + ".password");
        String maxconn = props.getProperty(poolName + ".maxconn", "0");
  //System.err.println("Url: " + url+" ,User:"+user+",password:"+password+",maxconn:"+maxconn+"...");
        int max;
        try {
          max = Integer.valueOf(maxconn).intValue();
        }
        catch (NumberFormatException e) {
          System.err.println("Invalid maxconn value " + maxconn + " for " +   poolName);
          max = 0;
        }
        DBConnectionPool pool =
          new DBConnectionPool(poolName, url, user, password, max);
        pools.put(poolName, pool);
       // System.err.println("Initialized pool " + poolName);
      }
    }
  }

  class DBConnectionPool {
    private int checkedOut;
    private Vector freeConnections = new Vector();
    private int maxConn;
    private String name;
    private String password;
    private String URL;
    private String user;

    /**
    * 创建新的连接池
    *
    * @param name 连接池名字
    * @param URL 数据库的JDBC URL
    * @param user 数据库帐号,或 null
    * @param password 密码,或 null
    * @param maxConn 此连接池允许建立的最大连接数
    */
    public DBConnectionPool(String name, String URL, String user
        , String password,   int maxConn)
    {
      this.name = name;
      this.URL = URL;
      this.user = user;
      this.password = password;
      this.maxConn = maxConn;
    }

  /**
  * 将不再使用的连接返回给连接池
  *
  * @param con 客户程序释放的连接
  */
    public synchronized void freeConnection(Connection con) {
    // 将指定连接加入到向量末尾
      freeConnections.addElement(con);
      checkedOut--;
      notifyAll();
    }

    /**
     * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接
     * 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
     * 然后递归调用自己以尝试新的可用连接.
     */
    public synchronized Connection getConnection()
    {
      Connection con = null;
      if (freeConnections.size() > 0)
      {
      // 获取向量中第一个可用连接
        con = (Connection) freeConnections.firstElement();
        freeConnections.removeElementAt(0);
        try {
          if (con.isClosed())
          {
            log("从连接池" + name+"删除一个无效连接");
            // 递归调用自己,尝试再次获取可用连接
            con = getConnection();
          }
        }
        catch (SQLException e)
        {
          log("从连接池" + name+"删除一个无效连接");
          // 递归调用自己,尝试再次获取可用连接
          con = getConnection();
        }
      }
      else if (maxConn == 0 || checkedOut < maxConn)
      {
        con = newConnection();
      }
      if (con != null) {
        checkedOut++;
      }
      return con;
    }

  /**
  * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间
  * 参见前一个getConnection()方法.
  *
  * @param timeout 以毫秒计的等待时间限制
  */
    public synchronized Connection getConnection(long timeout)
    {
      long startTime = new java.util.Date().getTime();
      Connection con;
      while ((con = getConnection()) == null)
      {
        try {
          wait(timeout);
        }
        catch (InterruptedException e) {}
        if ((new java.util.Date().getTime() - startTime) >= timeout)
        {
        // wait()返回的原因是超时
          return null;
        }
      }
      return con;
    }

  /**
  * 关闭所有连接
  */
    public synchronized void release()
    {
      Enumeration allConnections = freeConnections.elements();
      while (allConnections.hasMoreElements())
      {
        Connection con = (Connection) allConnections.nextElement();
        try {
        con.close();
          log("关闭连接池" + name+"中的一个连接");
        }
        catch (SQLException e) {
          log(e, "无法关闭连接池" + name+"中的连接");
        }
      }
      freeConnections.removeAllElements();
    }

  /**
  * 创建新的连接
  */
    private Connection newConnection()
    {
      Connection con = null;
      try {
        if (user == null) {
          con = DriverManager.getConnection(URL);
        }
        else {
          con = DriverManager.getConnection(URL, user, password);
        }
        //System.err.println("连接池" + name+"创建一个新的连接");
      }
      catch (SQLException e) {
        log(e, "无法创建下列URL的连接: " + URL);
        return null;
      }
      return con;
    }
  }
}

 

以下为dbop.java 源码

package com.china3cts;
import java.sql.*;
public class dbop
{
ResultSet rs = null;
public ResultSet execute(String sql)
{
 rs = null;
 try
  {
   DBConnectionManager connMgr;
   connMgr = DBConnectionManager.getInstance();
   Connection conn = connMgr.getConnection("china3cts");
   Statement stmt = conn.createStatement();
   rs = stmt.executeQuery(sql);
  }
 catch(SQLException ex)
  {
   System.err.println("查询出错: " + ex.getMessage());
  }
return rs;
}

public int update(String sql)
{
 int outn=0;
 try
  {
   DBConnectionManager connMgr;
   connMgr = DBConnectionManager.getInstance();
   Connection conn = connMgr.getConnection("china3cts");
   Statement stmt = conn.createStatement();
   outn=stmt.executeUpdate(sql);
  }
 catch(SQLException ex)
  {
   System.err.println("查询出错: " + ex.getMessage());
  }
return outn;
}
}

以下为db.properties 配置文件

drivers=org.gjt.mm.mysql.Driver
logfile=D://Tomcat//webapps//ROOT//logs//dbpool.log
china3cts.url=jdbc:mysql://localhost/china3cts
china3cts.user=root
china3cts.password=
china3cts.maxconn=1000

java文件javac后会生成如下几个文件

DBConnectionManager$DBConnectionPool.class
DBConnectionManager.class
dbop.class

各文件位置存放

class和db.properties请置于

/Web-inf/Classes/com/china3cts 目录下

以下是test.jsp

<%@ page contentType="text/html;charset=GBK"%>
<%@ page language="java" import="java.sql.*" %>
<%@ page language="java" import="com.china3cts.DBConnectionManager" %>
<%
Statement stmt = null;
DBConnectionManager connMgr;
connMgr = DBConnectionManager.getInstance();
Connection conn = connMgr.getConnection("china3cts");
if (conn!=null)
{
 out.print("good");
 String SQL="select id from sometable limit 1";
 stmt = conn.createStatement();
 ResultSet rs = null;
 rs=stmt.executeQuery(SQL);
 if (rs.next())
 {
  out.print(rs.getInt(1));
 }
 else
 {
  out.print("Error!");
 }
}
else
{
 out.print("worse");
}
%>

 

以下是test2.jsp 源码

<%@ page contentType="text/html;charset=GBK"%>
<%@ page language="java" import="java.sql.*" %>
<%@ page language="java" import="com.china3cts.*" %>
<%
ResultSet rs=null;
dbop conn=new dbop();
String SQL="select id from sometable limit 1";
rs=conn.execute(SQL);
if (rs.next())
{
 out.print(rs.getInt(1));
}
else
{
 out.print("Error!");
}

%>

 

注释与说明如下

0:DBConnectionManager为网上大虾所原创,原作者无从考究.

1:test.jsp 是单纯调用连接池测试, 实际应用的时候记得调用release方法清空一下

2:test2.jsp是测试我自己写的数据库操作扩展类,因为我以前是写ASP的.习惯了conn.execute,所以也顺便写个conn.execute 好一点.

3:二个测试程序应该得到同样的结果,只不过第一个程序多了一个good!

4:实际应用中请酌情使用dbop.java,这个是我自己写的.呵呵.

5:程序中或者源码中多次出现的china3cts

其中源码中打包出现的china3cts指的是包名.可以自行修改

而测试程序中出现的china3cts则是配置文件中的键名china3cts

已知bug

1 , 经过无数次测试,已知原DBConnectionManager.java源程序中的log好像无法使用.

我只把其中新获取连接中的log改成system.err.println

2,已有人称此连接池为假的并发连接池,是队列连接池.是真是假,无从判断.也没时间.

如果有大虾知道log如何调试好,麻烦告诉本人,谢谢,小弟弟MSN:info@hkeb.com QQ:3292957

非常感谢.

2006-07-03 于 凌晨4:30  深圳

 

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3cts

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值