andy Space

博客园 首页 新随笔 联系 订阅 管理

package mc;

import java.util.*;
import java.util.Date;
import java.sql.*;
import java.io.*;

public class DBConnectionManager {

 /** 日志文件写入流对象 */
 private PrintWriter log;

 /** 存放连接池对象Hashtable */
 private Hashtable pools;

 /** DBConnectionManager 唯一实例 */
 static private DBConnectionManager instance;

 /** 记录客户机的连接数 */
 static private int remotes;

 /** 存放数据库连接驱动 */
 private Vector drivers;


 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 私有构造方法<br>
  * 返回值:   无<br>
  * 参数说明: 无<br>
  * 创建人: andy<br>
  * 创建时间: 2006年9月1日
  * 最后修改: 无<br>
  */
 private DBConnectionManager()
 {
  init();
 }

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 初始化类属性<br>
  * 返回值:   无<br>
  * 参数说明: 无<br>
  * 创建人: andy<br>
  * 创建时间: 2006年9月1日
  * 最后修改: 无<br>
  */
 private void init()
 {
  pools = new Hashtable();
  drivers = new Vector();
                //建立属性对象
  Properties prop = new Properties();
                //把属性文件的属性列表读到属性对象
  try {
            InputStream is = getClass().getResourceAsStream("db.properties");
   prop.load(is);
  } catch (IOException e) {
   e.printStackTrace();
   System.out.println("读取属性文件错误!");
  }
  // 建立日志文件输入流对象
  String logFilePath = prop.getProperty("logFile");
  try {
   log = new PrintWriter(new FileWriter(logFilePath,true),true);
  } catch (IOException e) {
   e.printStackTrace();
   System.out.println("无法打开日志文件:" + logFilePath);
   log = new PrintWriter(System.err);
  }
  // 加载和注册数据库驱动
  loadDriver(prop);
  // 初始化和创建连接池实例
  createPools(prop);
 }


 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 返回 DBConnectionManager 唯一实例.如果是第一次调用此方法,则创建实例<br>
  * 返回值:   DBConnectionManager 对象<br>
  * 参数说明: 无<br>
  * 创建人: andy<br>
  * 创建时间:  2006年9月1日
  * 最后修改: 无<br>
  */
 static synchronized public DBConnectionManager getInstance()
 {
  if(instance == null){
   instance = new DBConnectionManager();
  }
  remotes++;
  return instance;
 }

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 把文本信息写入日志文件<br>
  * 返回值:   无<br>
  * 参数说明: String message 信息描述字符串<br>
  * 创建人: andy<br>
  * 创建时间:  2006年9月1日
  * 最后修改: 无<br>
  */
 private void logWriter(String message)
 {
  log.println("日期: " + new Date() + message);
 }

 private void logWriter(Throwable e,String errMessage)
 {
  log.println("日期: " + new Date() + errMessage + "\n错误: ");
  e.printStackTrace(log);    // 把异常描述写入日志文件
 }

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 获取一个数据库连接<br>
  * 返回值:   Connection类型<br>
  * 参数说明: String poolName 接收连接池名称<br>
  * 创建人: andy<br>
  * 创建时间:  2006年9月1日
  * 最后修改: 无<br>
  */
 public Connection getConnection(String poolName)
 {
  // 通过连接池名称返回连接池对象
  DBConnectionPool pool = (DBConnectionPool) pools.get(poolName);
  if(pool == null){
   logWriter("试图使用不存在的连接池" + poolName);
   return null;
  }
  // 返回连接给用户.
  return pool.getConnection();
 }

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能:  释放连接,把用完的连接归还给连接池<br>
  * 返回值:   无<br>
  * 参数说明: String poolName 连接池名称,Connection conn 连接对象<br>
  * 创建人: andy<br>
  * 创建时间: 2006年9月1日
  * 最后修改: 无<br>
  */
 public void RefeaseConnection(String poolName,Connection conn)
 {
  DBConnectionPool pool = (DBConnectionPool) pools.get(poolName);
  if(pool == null){
   logWriter("释放连错误!请检查连接池名称.");
   return;
  }else{
   pool.freeConnection(conn);
  }
 }

        /**
         * 类名:     DBConnectionManager<br>
         * 函数功能:  释放连接,把用完的连接归还给连接池<br>
         * 返回值:   无<br>
         * 参数说明: String poolName 连接池名称,Connection conn 连接对象<br>
         * 创建人: andy<br>
         * 创建时间: 2006年9月1日
         * 最后修改: 无<br>
  */
        public void RefeaseConnection
        (String poolName,Connection conn,Statement stn,PreparedStatement ptn,ResultSet result)
       {
               try {
                   if (stn != null)
                       stn.close();
                   if (ptn != null)
                       ptn.close();
                   if (result != null)
                       result.close();
               }catch(Exception ex)
               {
                   ex.printStackTrace(System.out);
                   System.out.println(ex.getMessage());
               }
               DBConnectionPool pool = (DBConnectionPool) pools.get(poolName);
               if(pool == null){
                       logWriter("释放连错误!请检查连接池名称.");
                       return;
               }else{
                       pool.freeConnection(conn);
               }

        }

 

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 释放所有的连接,注销驱动<br>
  * 返回值:   无<br>
  * 参数说明: 无<br>
  * 创建人: andy<br>
  * 创建时间: 2006年9月1日
  * 最后修改: 无<br>
  */
 public synchronized void releas()
 {
  if(--remotes != 0){
   return;
  }
  Enumeration ePools =  pools.elements();
  while(ePools.hasMoreElements()){
   DBConnectionPool pool = (DBConnectionPool) ePools.nextElement();
   //关闭所有的连接对象
   pool.release();
  }
  Enumeration eDrivers = drivers.elements();
  while(eDrivers.hasMoreElements()){
   Driver driver = (Driver) eDrivers.nextElement();
   try {
    DriverManager.deregisterDriver(driver);
    logWriter("注销" + driver.getClass().getName() + "成功!");
   } catch (SQLException e) {
    logWriter(e,"无法注销" + driver.getClass().getName() + "驱动!");
    e.printStackTrace();
   }
  }
 }

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 加载和注册数据库驱动程序<br>
  * 返回值:   无<br>
  * 参数说明: Properties prop变量接收数据库属性列表<br>
  * 创建人: andy<br>
  * 创建时间: 2006年9月1日
  * 最后修改: 无<br>
  */
 private void loadDriver(Properties prop)
 {
  // 从prop属性对象中取出驱动字符串
  String driverClass = prop.getProperty("drivers");
  // 把驱动字符串分解为标记
  StringTokenizer st = new StringTokenizer(driverClass);
  while(st.hasMoreTokens()){
   String driverClassName = st.nextToken().trim();
   try {
    // 加载数据库驱动
    Driver driver = (Driver) Class.forName(driverClassName).newInstance();
    // 注册数据库驱动
    DriverManager.registerDriver(driver);
    drivers.addElement(driver);
    // 把注册相关信息写入日志文件
    logWriter("成功注册数据库驱动.");
   } catch (InstantiationException e) {
    logWriter("加载数据库驱动错误:" + e.getMessage());
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    logWriter("加载数据库驱动错误:" + e.getMessage());
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    logWriter("加载数据库驱动错误:" + e.getMessage());
    e.printStackTrace();
   } catch (SQLException e) {
    logWriter("无法数据库驱动:" + e.getMessage());
    e.printStackTrace();
   }
  }
 }

 /**
  * 类名:     DBConnectionManager<br>
  * 函数功能: 初始化和建立连接池实例<br>
  * 返回值:   无<br>
  * 参数说明: Properties prop 变量接收设置连接池属性列表;如 最大连接数,最少连接数等<br>
  * 创建人: andy<br>
  * 创建时间: 2006年9月1日
  * 最后修改: 无<br>
  */
 private void createPools(Properties prop)
 {
  /** 返回属性列表中所有键的枚举 */
  Enumeration propNames = prop.propertyNames();
  while(propNames.hasMoreElements()){
   String name = (String) propNames.nextElement();
   if(name.endsWith(".url")){
    // propName 以后用做连接池名称
    String poolName = name.substring(0,name.indexOf("."));
    String url = prop.getProperty(poolName + ".url").trim();
    if(poolName == null || url == null){
     log.print("没有连接池:" + poolName + " 指定的URL");
     continue;
    }

    String user = prop.getProperty(poolName + ".user").trim();
    String password = prop.getProperty(poolName + ".password").trim();
    String strMaxConn = prop.getProperty(poolName + ".maxConn").trim();
                                String strMinConn = prop.getProperty(poolName + ".minConn").trim();
    int maxConn = 0,minConn = 0;
    try{
     maxConn = Integer.parseInt(strMaxConn);
                                        minConn = Integer.parseInt(strMinConn);
     }catch(NumberFormatException ne){
      maxConn = 100;
                                                minConn = 50;
      logWriter(ne," 属性文件中的最大连接数错误,请检查书写是否正确!" +
        "此错误出现后,系统自动设置最大连接数为100");
     }
    //取得数据库属性文件中的相关设置后开始建立连接池
    DBConnectionPool pool = new DBConnectionPool(poolName,url,user,password,maxConn,minConn);
    //把连接池放到 Hashtable
    pools.put(poolName, pool);
    logWriter("连接池创建成功!");
   }
  }
 }

 /**
  * 类名:       DBConnectionPool类是DBConnectionManager类的内部类<br>
  * 内部类功能:  此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最大连接数为止.
     在返回连接给客户程序之前,它能够验证连接的有效性.<br>
  * 返回值:    无<br>
  * 参数说明:  <br>
  * 创建人:  andy<br>
  * 创建时间:   2006年9月1日
  * 最后修改:  无<br>
  */
 class DBConnectionPool
 {
  /** 记录分出的连接数 */
  private int checkOut;

  /** 存放连接的 Vector 对象 */
  private Vector freeConnection;

  /** 数据库帐户 */
  private String user;

  /** 登陆密码 */
  private String password;

  /** 连接池名称 */
  private String poolName;

  /** 数据源URL */
  private String url;

  /** 最大连接数 */
  private int maxConn;

                /** 最小连接数 */
                private int minConn;

  /**
   * 类名:     DBConnectionPool<br>
   * 函数功能: 构造方法<br>
   * 返回值:   无<br>
   * 参数说明: String poolName 接收连接池名称; String url 数据源URL;
       String user 数据库帐户; String password 密码; int maxConn 设置最大的连接数<br>
   * 创建人: andy<br>
   * 创建时间: 2006年9月1日
   * 最后修改: 无<br>
   */
  public DBConnectionPool(String poolName, String url, String user,
    String password, int maxConn,int minConn) {

   freeConnection = new Vector();
   this.poolName = poolName;
   this.url = url;
   this.user = user;
   this.password = password;
   this.maxConn = maxConn;
                        this.minConn = minConn;
                        init();
  }


                /**
                 * 类名:     DBConnectionPool<br>
                 * 函数功能: 该方法在程序第一次运行时生成最小连接数。<br>
                 * 返回值:   Connection 对象<br>
                 * 参数说明: 无<br>
                 * 创建人: andy<br>
                 * 创建时间: 2006年9月1日
                 * 最后修改: 无<br>
                 */

                private void init() {
                     Connection conn = null;
                    for (int i = 0; i < minConn; i++) {
                        try {
                            conn = DriverManager.getConnection(url, user, password);
                            logWriter("连接池: " + poolName + " 创建了一个新连接");
                        } catch (SQLException e) {
                            logWriter(e, "无法建立:" + url + "连接");
                            e.printStackTrace();
                        }
                        freeConnection.addElement(conn);
                    }
                }

  /**
   * 类名:     DBConnectionPool<br>
   * 函数功能: 返回连接对象<br>
   * 返回值:   Connection 对象<br>
   * 参数说明: 无<br>
   * 创建人: andy<br>
   * 创建时间: 2006年9月1日
   * 最后修改: 无<br>
   */
  public Connection getConnection(){
   Connection conn = null;

   if(freeConnection.size() > 0){
    //当连接池中有空闲的连接,就从池中取出一条连接
    conn = (Connection) freeConnection.firstElement();
    //连接取出后,从连接池中删除该连接的记录.
    freeConnection.removeElementAt(0);
    try {
     //判断所取出的连接是否有效
     if(conn.isClosed()){
      logWriter("从连接池 "+ poolName +" 中删除一条无效的连接");
      //递归调用自己,获取可用的连接
      conn = getConnection();
     }
    } catch (SQLException e) {
     logWriter("从连接池 "+ poolName +" 中删除一条无效的连接");
     e.printStackTrace();
     //递归调用自己,获取可用的连接
     conn = getConnection();
    }
    // 当连接池中没有可用的连接,且当前的连接数在设置最大的连接数以下.新建一个连接
   }else if(checkOut < maxConn){
    conn = newConnection();
    // 当连接池中没有可用的连接,且当前连接已经达到最大连接数.
   }else{
    try {
     Thread.sleep(500);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    //等待500毫秒后,递归调用自己,获取可用的连接
    conn = getConnection();
   }
   // 记录分出去的连接数
   checkOut++;
   return conn;
  }

  /**
   * 类名:     DBConnectionPool<br>
   * 函数功能: 返回新建的连接对象<br>
   * 返回值:   Connection 对象<br>
   * 参数说明: 无<br>
   * 创建人: andy<br>
   * 创建时间: 2006年9月1日
   * 最后修改: 无<br>
   */
  public Connection newConnection(){
   Connection conn = null;
   try {
    conn = DriverManager.getConnection(url,user,password);
    logWriter("连接池: " + poolName + " 创建了一个新连接");
   } catch (SQLException e) {
    logWriter(e,"无法建立:" + url + "连接");
    e.printStackTrace();
   }
   return conn;
  }

  /**
   * 类名:     DBConnectionPool<br>
   * 函数功能: 释放连接对象<br>
   * 返回值:   无<br>
   * 参数说明: 无<br>
   * 创建人: andy<br>
   * 创建时间: 2006年9月1日
   * 最后修改: 无<br>
   */
  synchronized public void freeConnection(Connection conn)
  {
   // 把连接对象放回 Vector 里
   freeConnection.addElement(conn);
   // 连接数减1
   checkOut--;
   // 唤醒在此对象监视器上等待的所有线程
   notifyAll();
  }

  public synchronized void release()
  {
   Enumeration allConn = freeConnection.elements();
   while(allConn.hasMoreElements()){
    Connection conn = (Connection) allConn.nextElement();
    try {
     conn.close();
     logWriter("成功关闭连接!");
    } catch (SQLException e) {
     logWriter(e,"无法关闭连接池" + poolName + "中连接!");
     e.printStackTrace();
    }
    //清空 Vector 中的所有元素
    freeConnection.removeAllElements();
   }
  }
 }
}

posted on 2006-12-15 23:20  andyliang  阅读(3130)  评论(1编辑  收藏  举报