`
aaron_ch
  • 浏览: 177306 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Java Connect Pool

    博客分类:
  • Java
阅读更多
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验证通过

方法调用!

package com.xinnuo.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DBConn {
private DBConnectionManager connMgr = null;
private Connection conn = null;
private Statement stat = null;
private ResultSet rs = null;
public DBConn() {
  connMgr = DBConnectionManager.getInstance();
}
public ResultSet executeQuery(String strSQL) throws SQLException {
  this.conn = connMgr.getConnection("access");
  this.stat = this.conn.createStatement();
  this.rs = this.stat.executeQuery(strSQL);
  return this.rs;
}
public void execute(String strSQL) throws SQLException {
  this.conn = connMgr.getConnection("access");
  this.stat = this.conn.createStatement();
  this.stat.execute(strSQL);
}
public void executeUpdate(String strSQL) throws SQLException {
  this.conn = connMgr.getConnection("access");
  this.stat = this.conn.createStatement();
  this.stat.executeUpdate(strSQL);
}
public Connection getConnection(){
  this.conn = connMgr.getConnection("access");
  return this.conn;
}
public void free(){
  try {
   if (this.rs != null) {
    this.rs.close();
   }
   if (this.stat != null) {
    this.stat.close();
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }
  connMgr.freeConnection("access", this.conn);
}
}

分享到:
评论

相关推荐

    java 连接sqlserver使用的java-sqlserver-connect.jar包

    在本例中,我们关注的是"java-sqlserver-connect.jar",这是一个专门为Java应用程序提供与Microsoft SQL Server数据库交互功能的库。这个JAR文件支持两个不同的Java运行时环境(JRE),即JRE7和JRE8。 首先,了解...

    mysql connect pool

    `DispacherPersistSuport.java`和`JdbcHelper.java`这两个类可能结合使用,通过`DataSourcePool.java`来获取和释放数据库连接。`JdbcHelper.java`可能包含了一些静态方法,使得开发者可以通过简单的调用来执行SQL...

    浅谈Java内部类的四个应用场景

    为了实现这一目标,我们可以通过定义一个`ConnectPool`类来管理一系列数据库连接,并且在这个类中定义一个内部类`PoolConn`来表示每个数据库连接的状态信息。 首先定义一个接口`Pool`,用来规定数据库连接池应该...

    jdbc connection pool

    ### JDBC Connection Pool 实现 #### 一、简介 在Java应用程序中,数据库连接是非常宝贵的资源。为了提高性能和效率,通常会使用连接池技术来管理这些数据库连接。连接池可以复用现有的数据库连接,避免频繁地创建...

    功能完善的Java连接池调用实例

    在给定的代码示例中,我们看到一个名为`ConnectPool`的类,它是连接池的管理器,负责管理多个数据库连接池。这个类实现了单例设计模式,确保在整个应用程序中只有一个`ConnectPool`实例存在。单例模式可以避免多个...

    java连接Redis所需jar包

    总的来说,Java连接Redis主要依赖于Jedis库和Apache Commons Pool库。通过这两个库,开发者可以轻松地在Java应用程序中集成Redis,执行各种操作,同时利用对象池提高性能。正确配置和使用这些库,对于实现高效、稳定...

    JavaConnect:Java 8中的并发并使用与并发相关的库

    以下是对`JavaConnect`项目中涉及的并发知识的详细说明。 1. **Fork/Join框架**: Java 8引入了Fork/Join框架,它基于工作窃取算法,用于将大任务拆分为小任务,然后并行执行这些子任务。`ForkJoinPool`是主要的...

    JAVA连接redis进行操作的DEMO源码(2016)

    在本文中,我们将深入探讨如何使用Java连接并操作Redis分布式缓存数据库。Redis是一个高性能的键值存储系统,常用于缓存、消息队列、事件发布/订阅等场景。Java作为广泛使用的编程语言,提供了丰富的客户端库来与...

    JAVA链接Redis需要使用到的jar包

    这里提到的"JAVA链接Redis需要使用的jar包"主要包括两个关键组件:`jedis-2.1.0.jar`和`commons-pool-1.6.jar`。 1. **Jedis**: Jedis是Java开发的一个轻量级Redis客户端,它提供了丰富的Redis命令支持,方便Java...

    SAP Java Connector(JCo).doc

    mConnection.connect(); mConnection.disconnect(); } catch (Exception ex) { } } ``` 在这段代码中,`createClient()`方法用于创建连接,参数包括SAP客户端号、用户名、密码、语言、服务器主机名和系统编号...

    redis java调用代码

    为了提高性能,通常会使用连接池管理Redis连接,例如使用JedisPool(Jedis)或GenericObjectPoolConfig(Lettuce)。 四、异步操作 Lettuce支持异步API,可以实现非阻塞的Redis操作。 ```java RedisAsyncCommands,...

    mongo-java-driver最新jar.zip

    mongo-java-driver3.0以上jar压缩包大全 try { //1.连接池相关选项配置 MongoClientOptions options=MongoClientOptions.builder() .connectionsPerHost(poolSize) .minConnectionsPerHost(minpoolsize) ...

    IBM Java socket教程

    在Java中,`java.sql.ConnectionPoolDataSource`和`javax.sql.PooledConnection`接口用于数据库连接池,而对于Socket连接池,开发者可以使用第三方库如Apache Commons Pool或HikariCP。连接池的主要优点是减少资源...

    学习java数据库连接池.pdf

    public SimpleDBPool(int maxPoolSize, IDataBase db) { this.maxPoolSize = maxPoolSize; this.connector = new DBConnector(db); } /** * 初始化连接池,创建指定数量的数据库连接 */ public void initPool() { ...

    java数据库连接池

    Java数据库连接池(JDBC Connection Pool)是一种管理数据库连接的技术,它允许应用程序重复使用已经存在的数据库连接,而不是每次需要时都创建新的连接。这大大提高了应用程序的性能和效率,因为创建和销毁数据库...

    java_connetto_Mysql.rar_MYSQL_ROOT_java mysql

    这个"java_connect_to_Mysql.rar"压缩包显然包含了有关如何使用Java连接到MySQL数据库,特别是使用连接池技术的相关资源。让我们深入探讨一下这个主题。 首先,连接池是一种管理数据库连接的机制,它允许程序重复...

Global site tag (gtag.js) - Google Analytics