package com.common.pool; import java.io.*; import java.sql.*; import java.util.*; import java.util.Date; /** * 管理类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(); } /** * 读取属性完成初始化 */ 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", "dbconMgr.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 参数 : db.properties */ 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); } } } /** * 根据指定属性创建连接池实例. * @param 参数 : db.properties */ 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); } } } /** * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 053 * 限制,则创建并返回新连 * @param name在属性文件中定义的连接池名字 056 * * @return Connection 可用连接或null 057 */ public Connection getConnection(String poolname) { DBConnectionPool pool = (DBConnectionPool) pools.get(poolname); if (pool != null) { return pool.getConnection(); } return null; } /** * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接. * @param name 连接池名字 071 * * @param time以毫秒计的等待时间 * @return Connection 可用连接或null */ public Connection getConnection(String poolename, long time) { DBConnectionPool pool = (DBConnectionPool) pools.get(poolename); if (pool != null) { return pool.getConnection(time); } return null; } /** * * 将连接对象返回给由名字指定的连接池 * @param name在属性文件中定义的连接池名字 * @param con连接对象 */ public void freeConnection(String poolname, Connection con) { DBConnectionPool pool = (DBConnectionPool) pools.get(poolname); if (pool != null) { pool.freeConnection(con); } } /** * 关闭所有连接,撤销驱动程序的注册 */ 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()); } } } /** * 将文本信息写入日志文件 */ public void log(String msg) { log.println(new Date() + ": " + msg); } /** * 将文本信息与异常写入日志文件 */ public void log(Throwable e, String msg) { log.println(new Date() + ": " + msg); e.printStackTrace(log); } // /////////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////////////////// /** * 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最大连接数 */ class DBConnectionPool { private int checkedOut; private Vector freeConnections = new Vector(); private int maxConn; private String poolname; 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 poolname, String URL, String user, String password, int maxConn) { this.poolname = poolname; this.URL = URL; this.user = user; this.password = password; this.maxConn = maxConn; } /** * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接 数限制,则创建新连接. * 如原来登记为可用的连接不再有效,则从向量删除之, 然后递归调用自己以尝试新的可用连接. */ public synchronized Connection getConnection() { Connection con = null; if (freeConnections.size() > 0) {// 获取向量中第一个可用连接 con = (Connection) freeConnections.firstElement(); freeConnections.removeElementAt(0); try { if (con.isClosed()) { log("从连接池" + poolname + "删除一个无效连接"); // 递归调用自己,尝试再次获取可用连接 con = getConnection(); } } catch (SQLException e) { log("从连接池" + poolname + "删除一个无效连接"); // 递归调用自己,尝试再次获取可用连接 con = getConnection(); } } else if (maxConn == 0 || checkedOut < maxConn) { con = newConnection(); } if (con != null) { checkedOut++; } log("从连接池" + poolname + "获取一个连接"); 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; } } log("从连接池" + poolname + "获取一个连接"); return con; } /** * 创建新的连接 */ private Connection newConnection() { Connection con = null; try { if (user == null || "".equals(user)) { con = DriverManager.getConnection(URL); } else { con = DriverManager.getConnection(URL, user, password); } log("连接池" + poolname + "创建一个新的连接"); } catch (SQLException e) { log(e, "无法创建下列URL的连接: " + URL); return null; } return con; } /** * 将不再使用的连接返回给连接池 * @param con客户程序释放的连接 */ public synchronized void freeConnection(Connection con) { // 将指定连接加入到向量末尾 freeConnections.addElement(con); checkedOut--; log("从连接池" + poolname + "增加一个连接"); notifyAll(); } /** * 关闭所有连接 */ public synchronized void release() { Enumeration allConnections = freeConnections.elements(); while (allConnections.hasMoreElements()) { Connection con = (Connection) allConnections.nextElement(); try { con.close(); log("关闭连接池" + poolname + "中的一个连接"); } catch (SQLException e) { log(e, "无法关闭连接池" + poolname + "中的连接"); e.printStackTrace(); } } freeConnections.removeAllElements(); } } }

s569891514 LV2
2018年1月10日
AXIN LV36
2014年2月12日

cccccc1235
2024年5月20日
暂无贡献等级
y1214435276 LV9
2024年4月11日
xianyu091012 LV5
2023年7月19日
胡明杨
2023年4月22日
暂无贡献等级
不正经的90后程序猿 LV1
2022年12月24日
李海洋 LV12
2022年8月7日
17798830 LV14
2022年1月27日
15368725041
2021年8月13日
暂无贡献等级
qaplbgh
2021年6月15日
暂无贡献等级
CoderMars LV13
2021年6月13日