`
zhouxing
  • 浏览: 208517 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

连接池

阅读更多

package com.xinnuo.jdbc;

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

 /*
  * 该类只能创建一个实例,其它对象能够调用其静态方法(也称为类方法)获得该唯一实例的引用。
  * DBConnectionManager类的建构函数是私有的,这是为了避免其它对象创建该类的实例.
  * DBConnectionManager类的客户程序可以调用getInstance()方法获得对该类唯一实例的引用。
  * 类的唯一实例在getInstance()方法第一次被调用期间创建,此后其引用就一直保存在静态变量
  * instance中。每次调用getInstance()都增加一个DBConnectionManager的客户程序计数。
  * 即,该计数代表引用DBConnectionManager唯一实例的客户程序总数,它将被用于控制连接池的
  * 关闭操作。 该类实例的初始化工作私有方法init()完成。其中 getResourceAsStream()方法
  * 用于定位并打开外部文件。外部文件的定位方法依赖于类装载器的实现。标准的本地类装载器查找操
  * 作总是开始于类文件所在路径,也能够搜索CLASSPATH中声明的路径。db.properties是一个属性
  * 文件,它包含定义连接池的键-值对。可供定义的公用属性如下:
  *   drivers 以空格分隔的JDBC驱动程序类列表\\
  *   logfile 日志文件的绝对路径
  *  其它的属性和特定连接池相关,其属性名字前应加上连接池名字:
  *  < poolname>.url 数据库的 JDBC URL
  *  < poolname>.maxconn 允许建立的最大连接数,0表示没有限制
  *  < poolname>.user 用于该连接池的数据库帐号
  *  < poolname>.password 相应的密码\\
  * 其中url属性是必需的,而其它属性则是可选的。数据库帐号和密码必须合法。用于Windows平台的
  * db.properties文件示例如下:
  *  drivers=com.microsoft.jdbc.sqlserver.SQLServerDriver
  *  logfile=D:\\log.txt
  *  access.maxconn=20
  *  access.url=jdbc:microsoft:sqlserver://localhost:1433;databasename=web
  *  access.user=sa
  *  access.password=sa 
  * 注意在Windows路径中的反斜杠必须输入2个,这是由于属性文件中的反斜杠同时也是一个转义字符。
  * init()方法在创建属性对象并读取db.properties文件之后,就开始检查logfile属性。如果属
  * 性文件中没有指定日志文件,则默认为当前目录下的DBConnectionManager.log文件。如日志文
  * 件无法使用,则向System.err输出日志记录。装载和注册所有在drivers属性中指定的JDBC驱动
  * 程序loadDrivers()方法实现。该方法先用StringTokenizer将drivers属性值分割为对应于驱
  * 动程序名称的字符串,然后依次装载这些类并创建其实例,最后在DriverManager中注册该实例并把
  * 它加入到一个私有的向量drivers。向量drivers将用于关闭服务时从DriverManager取消所有
  * JDBC 驱动程序的注册。init()方法的最后一个任务是调用私有方法createPools()创建连接池对
  * 象。createPools()方法先创建所有属性名字的枚举对象(即Enumeration对象,该对象可以想象
  * 为一个元素系列,逐次调用其nextElement()方法将顺序返回各元素),然后在其中搜索名字以“.url”
  * 结尾的属性。对于每一个符合条件的属性,先提取其连接池名字部分,进而读取所有属于该连接池的属性,
  * 最后创建连接池对象并把它保存在实例变量pools中。散列表(Hashtable类 )pools实现连接池名字
  * 到连接池对象之间的映射,此处以连接池名字为键,连接池对象为值。 为便于客户程序从指定连接池获
  * 得可用连接或将连接返回给连接池,类DBConnectionManager提供了方法getConnection()和
  * freeConnection()。所有这些方法都要求在参数中指定连接池名字,具体的连接获取或返回操作则调
  * 用对应的连接池对象完成。为实现连接池的安全关闭,DBConnectionManager提供了方法release()。
  * 在上面我们已经提到,所有DBConnectionManager的客户程序都应该调用静态方法getInstance()
  * 以获得该管理器的引用,此调用将增加客户程序计数。客户程序在关闭时调用release()可以递减该计数。
  * 当最后一个客户程序调用release(),递减后的引用计数为0,就可以调用各个连接池的release()方法
  * 关闭所有连接了。管理类release()方法最后的任务是撤销所有JDBC驱动程序的注册。
  */

/**
 * 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接
 * 池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例.
 */
public class DBConnectionManager {
 static private DBConnectionManager instance; // 唯一实例

 static private int clients;

 private Vector drivers = new Vector();

 private PrintWriter log;

 private Hashtable pools = new Hashtable();

 /**
  * 返回唯一实例.如果是第一次调用此方法,则创建实例
  * @return DBConnectionManager 唯一实例
  */
 static synchronized public DBConnectionManager getInstance() {
  if (instance == null) {
   instance = new DBConnectionManager();
  }
  clients++;
  return instance;
 }

 /**
  * 建构函数私有以防止其它对象创建本类实例
  */
 private DBConnectionManager() {
  init();
 }

 /**
  * * 将连接对象返回给由名字指定的连接池
  * @param name在属性文件中定义的连接池名字
  * @param con连接对象\\\\r
  */
 public void freeConnection(String name, Connection con) {
  DBConnectionPool pool = (DBConnectionPool) pools.get(name);
  if (pool != null) {
   pool.freeConnection(con);
  }
 }

 /**
  * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 053 * 限制,则创建并返回新连
  * @param name在属性文件中定义的连接池名字 056 *
  * @return Connection 可用连接或null 057
  */
 public Connection getConnection(String name) {
  DBConnectionPool pool = (DBConnectionPool) pools.get(name);
  if (pool != null) {
   return pool.getConnection();
  }
  return null;
 }

 /**
  * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
  * 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
  * @param name 连接池名字 071 *
  * @param time以毫秒计的等待时间\\\\r
  * @return Connection 可用连接或null
  */
 public Connection getConnection(String name, long time) {
  DBConnectionPool pool = (DBConnectionPool) pools.get(name);
  if (pool != null) {
   return pool.getConnection(time);
  }
  return null;
 }

 /**
  * 关闭所有连接,撤销驱动程序的注册\\\\r
  */
 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());
   }
  }
 }

 /**
  * 根据指定属性创建连接池实例.
  * @param props 连接池属性 113
  */
 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) {
     log("没有为连接池" + poolName + "指定URL");
     continue;
    }
    String user = props.getProperty(poolName + ".user");
    String password = props.getProperty(poolName + ".password");
    String maxconn = props.getProperty(poolName + ".maxconn", "0");
    int max;
    try {
     max = Integer.valueOf(maxconn).intValue();
    } catch (NumberFormatException e) {
     log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);
     max = 0;
    }
    DBConnectionPool pool = new DBConnectionPool(poolName, url,
      user, password, max);
    pools.put(poolName, pool);
    log("成功创建连接池" + poolName);
   }
  }
 }

 /**
  * 读取属性完成初始化
  */
 private void init() {
  InputStream is = getClass().getResourceAsStream("/db.properties");
  Properties dbProps = new Properties();
  try {
   dbProps.load(is);
  } catch (Exception e) {
   System.err.println("不能读取属性文件. "+"请确保db.properties在CLASSPATH指定的路径中");
   return;
  }
  String logFile = dbProps.getProperty("logfile","DBConnectionManager.log");
  try {
   log = new PrintWriter(new FileWriter(logFile, true), true);
  } catch (IOException e) {
   System.err.println("无法打开日志文件: " + logFile);
   log = new PrintWriter(System.err);
  }
  loadDrivers(dbProps);
  createPools(dbProps);
 }

 /**
  * 装载和注册所有JDBC驱动程序
  * @param props属性
  */
 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);
    log("成功注册JDBC驱动程序" + driverClassName);
   } catch (Exception e) {
    e.printStackTrace();
    log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e);
   }
  }
 }

 /**
  * 将文本信息写入日志文件
  */
 private void log(String msg) {
  log.println(new Date() + ": " + msg);
 }

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

 // ///////////////////////////////////////////////////////////////////////////////////////////////////////
 // ///////////////////////////////////////////////////////////////////////////////////////////////////////
 /*
  * DBConnectionPool实现,它表示指向某个数据库的连接池。数据库由JDBC URL标识。一个JDBCURL由三部分组成:协议标识(总是jdbc),
  * 驱动程序标识(如odbc、idb、oracle等),数据库标识(其格式依赖于驱动程序)。例如,jdbc:odbc:demo,即是一个指向demo数据
  * 库的JDBCURL,而且访问该数据库要使用JDBC-ODBC驱动程序。每个连接池都有一个供客户程序使用的名字以及可选的用户帐号、密码、最
  * 大连接数限制。如果Web应用程序所支持的某些数据库操作可以被所有用户执行,而其它一些操作应由特别许可的用户执行,则可以为两类操作
  * 分别定义连接池,两个连接池使用相同的JDBC URL,但使用不同的帐号和密码。类DBConnectionPool的建构函数需要上述所有数据作为其
  * 参数。客户程序可以使用DBConnectionPool
  * 类提供的两个方法获取可用连接。两者的共同之处在于:如连接池中存在可用连接,则直接返回,否则创建新的连接并返回。如果没有可用连接
  * 且已有连接总数等于最大限制数,第一个方法将直接返回null,而第二个方法将等待直到有可用连接为止。所有的可用连接对象均登记在名为
  * freeConnections的向量(Vector)中。如果向量中有多于一个的连接,getConnection()总是选取第一个。同时,由于新的可用连接总
  * 是从尾部加入向量,从而使得数据库连接由于长时间闲置而被关闭的风险减低到最小程度。 第一个getConnection()在返回可用连接给客户
  * 程序之前,调用了isClosed()方法验证连接仍旧有效。如果该连接被关闭或触发异常,getConnection()递归地调用自己以尝试获取另外的
  * 可用连接。如果在向量freeConnections中不存在任何可用连接,getConnection()方法检查是否已经指定最大连接数限制。如已经指定,
  * 则检查当前连接数是否已经到达极限。此处maxConn为0表示没有限制。如果没有指定最大连接数限制或当前连接数小于该值,该方法尝试创建
  * 新的连接。如创建成功,则增加已使用连接的计数并返回,否则返回空值。创建新连接由newConnection()方法实现。
  * 创建过程与是否已经指定数据库帐号、密码有关。JDBC的DriverManager类提供多个getConnection()方法,这些方法要用到JDBC URL
  * 与其它一些参数,如用户帐号和密码等。DriverManager将使用指定的JDBC URL确定适合于目标数据库的驱动程序及建立连接。
  * 第二个getConnection()方法需要一个以毫秒为单位的时间参数,该参数表示客户程序能够等待的最长时间。建立连接的具体操
  * 作仍旧由第一个getConnection()方法实现。该方法执行时先将startTime初始化为当前时间。在while循环中尝试获得一个连接。如果失
  * 败,则以给定的时间值为参数调用wait()。wait()的返回可能是由于其它线程调用notify()或notifyAll(),也可能是由于预定时间已到。
  * 为找出wait()返回的真正原因,程序用当前时间减开始时间(startTime),如差值大于预定时间则返回空值,否则再次调用getConnection()。
  * 把空闲的连接登记到连接池由freeConnection()方法实现,它的参数为返回给连接池的连接对象。该对象被加入到freeConnections
  * 向量的末尾,然后减少已使用连接计数。调用notifyAll()是为了通知其它正在等待可用连接的线程。 许多Servlet引擎为实现安全关闭提供
  * 多种方法。数据库连接池需要知道该事件以保证所有连接能够正常关闭。DBConnectionManager类负协调整个关闭过程,但关闭连接池中所有连
  * 接的任务则由DBConnectionPool类负责。release()方法供DBConnectionManager调用。该方法遍历freeConnections向量并关闭所有连接,
  * 然后从向量中删除这些连接。
  */

 /**
  * 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最\\\\r
  */
 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 Date().getTime();
   Connection con;
   while ((con = getConnection()) == null) {
    try {
     wait(timeout);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    if ((new 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 + "中的连接");
     e.printStackTrace();
    }
   }
   freeConnections.removeAllElements();
  }

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

 /////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////////
}

在sqlserver2000,tomcat5.5验证通过

分享到:
评论

相关推荐

    连接池案例 连接池案例

    在IT行业中,数据库连接池是优化数据库访问性能和资源管理的重要技术。连接池的基本思想是重用已建立的数据库连接,避免频繁创建和销毁连接带来的性能开销。本篇文章将深入探讨连接池的概念、工作原理以及如何在实际...

    kafka生产者连接池

    为了优化性能和提高效率,开发人员常常会利用连接池技术来管理Kafka生产者的连接。本文将深入探讨"Kafka生产者连接池"的概念、实现原理以及它如何提升系统性能。 Kafka生产者连接池是一种资源复用机制,它允许多个...

    okhttp中连接池实现

    它的核心特性之一就是连接池(Connection Pool),它在提高网络性能和减少延迟方面起到了关键作用。本文将深入探讨OkHttp中的连接池实现,包括连接对象的添加、移除机制以及其工作原理。 首先,我们需要了解什么是...

    java ftp连接池

    Java FTP连接池是一种用于管理FTP(文件传输协议)连接的资源池,它的主要目标是提高应用程序的性能和效率。在传统的FTP操作中,每次需要连接到FTP服务器时都会创建一个新的连接,这会消耗大量时间和系统资源。而...

    tomcat连接池与阿里Druid连接池

    Tomcat 连接池和阿里 Druid 连接池的配置和比较 Tomcat 连接池是一种基于 Java 的数据库连接池实现,提供了高效、可靠的数据库连接管理。阿里 Druid 连接池是阿里巴巴开发的开源连接池,提供了高性能、可靠的数据库...

    Mongodb连接池for java

    在标签中,“MongoDB”是数据库的名字,“Mongo连接池”指的是针对MongoDB数据库的连接池,“连接池”是数据库连接管理的一个通用概念,适用于各种数据库系统。 在压缩包“mongodb_pool”中,可能包含了以下内容: ...

    C#高效数据库连接池源码

    数据库连接池是数据库管理中的重要概念,特别是在高并发和大数据量的应用场景下,它能显著提升性能并降低系统资源消耗。在C#编程环境中,我们可以使用自定义的数据库连接池来实现这一功能。本篇文章将深入探讨“C#...

    java 数据库 连接池驱动.rar

    Java数据库连接池驱动是Java应用程序在访问数据库时用于优化资源管理的一种技术。它提供了一种在多个数据库操作之间重用数据库连接的方式,从而避免了频繁创建和关闭连接带来的性能开销。连接池的核心思想是池化资源...

    Tomcat连接池配置.doc

    Tomcat 连接池配置详解 Tomcat 连接池配置是 Web 应用程序中一个非常重要的组件,它负责管理和维护数据库连接,确保数据访问的高速和安全性。本文将详细介绍 Tomcat 连接池配置的步骤和原理,帮助读者快速掌握 ...

    RabbitMQ客户端连接池的原理及源码

    本文将深入探讨RabbitMQ客户端连接池的工作原理,并分析其源码,以期帮助读者理解如何有效地利用连接池优化系统性能。 连接池的基本思想是预先创建一定数量的连接并保持空闲状态,当应用需要时可以从池中获取,使用...

    C# 数据库连接池 C# 数据库连接池

    数据库连接池是数据库管理中的一个重要概念,它在C#编程中扮演着优化数据库操作的关键角色。C#数据库连接池是一种管理数据库连接的技术,通过复用已存在的连接而不是每次请求时都创建新的连接,从而提高数据库操作的...

    spring中 连接池的使用

    在Spring框架中,数据库连接池是管理数据库连接的关键组件,它能有效地提高应用程序的性能和资源利用率。在上述内容中,提到了两种常用的连接池实现:Apache的DBCP(BasicDataSource)和C3P0(ComboPooledDataSource...

    c# mysql数据库连接池实现

    在.NET Core 2.1框架下,可以使用.NET Standard库来实现高效、优化的数据库连接管理,特别是通过连接池来提高性能。本文将深入探讨如何在C#中使用MySQL数据库连接池。 首先,我们需要了解什么是数据库连接池。...

    数据库连接池技术详解

    对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。 在较为完备的数据库连接池实现中,可根据...

    MySql数据库连接池C#代码(有注释含测试代码)

    MySQL数据库连接池是提高应用程序性能的一种重要技术,它允许开发者管理多个数据库连接并高效地复用这些连接,而不是每次需要时都创建新的连接。在C#编程中,我们可以使用自定义的连接池或者第三方库如ADO.NET的...

    socket 客户端连接池实现

    Socket客户端连接池是一种在分布式系统或网络编程中提高性能和效率的重要技术。它允许应用程序预先创建并维护一组可重用的Socket连接,从而避免了每次通信时建立新连接的开销。本文将深入探讨Socket客户端连接池的...

    使用连接池技术时的配置

    使用连接池技术时的配置 在本文中,我们将讨论使用连接池技术时的配置,特别是关于 Tomcat、MySQL 和 Eclipse 的数据库连接池配置。 一、开发工具介绍 为了配置连接池,我们需要使用以下开发工具: * Tomcat ...

    java socket连接池 实现

    Java Socket 连接池实现是提高网络应用性能和效率的关键技术之一。在高并发的网络环境中,频繁地创建和销毁Socket连接会导致大量的系统资源浪费,影响整体性能。为了解决这个问题,开发人员通常会使用连接池来管理和...

    oracle 数据库,在C++中用连接池实现高速连接与访问.rar

    2. 创建连接池:通过oci池化函数ociPoolCreate创建连接池,指定最小、最大连接数以及空闲连接超时时间。 3. 获取连接:当需要访问数据库时,从连接池中获取一个已建立的连接,而不是每次都新建。 4. 使用连接:执行...

Global site tag (gtag.js) - Google Analytics