日期:2014-05-16  浏览次数:20522 次

数据库连接池的java实现

connectionPool.DBConnectionManager

package connectionPool;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import connectionPool.util.Logger;
import connectionPool.util.PropertiesMgr;

/**
 * 连接池的设计思路
 * 1、
 * 初始化固定数目的连接(空闲连接与活跃连接在同一池中),建立连接的代理类,添加busy与startTime属性以便分发与回收连接
 * 另建立守护线程回收失效连接
 * 2、
 * 维护一空闲连接池,初始为空,需要连接时建立,用完的连接回收进入空闲连接池;
 * 后续所需连接从空闲连接池获取;activeNum记录活跃连接数目;
 * 当空闲连接池为空且活跃连接数达到上限时,请求等待,超时即获取连接失败,超时前有连接被释放方可获得连接
 * 第二个设计巧妙优势明显,采用第二种方式
 * 
 * 数据库连接管理类,单例模式
 * 可以管理加载多个数据库驱动,维护多个数据库连接池
 * @author shijin
 *
 */
public class DBConnectionManager {
	
	private static DBConnectionManager dbm = null;
	
	//单例模式里的成员变量都相当于是static了?
	/**
	 * 客户数目
	 */
	private static int clients = 0;
	/**
	 * 加载的驱动器集合
	 */
	private Set<Driver> drivers = new HashSet<Driver>();
	/**
	 * 数据库连接池字典
	 */
	private Hashtable<String,DBConnectionPool> pools = new Hashtable<String,DBConnectionPool>();
	
	private final Logger log = Logger.getInstance(DBConnectionPool.class);
	
	private DBConnectionManager() {
		loadDrivers();
		createPools();
	}

	/**
	 * 装载和注册所有的JDBC驱动程序
	 */
	private void loadDrivers() {
		String str_drivers = PropertiesMgr.getProperty("driver");
		for(String str_driver:str_drivers.split("\\s")) {
			Driver driver = null;
			try {
				driver = (Driver)Class.forName(str_driver).newInstance();
				DriverManager.registerDriver(driver);
				log.info("成功加载JDBC驱动:" + str_driver);
			} catch (InstantiationException e) {
				log.error("加载JDBC驱动" + str_driver + "时初始化异常,请检查配置文件");
			} catch (IllegalAccessException e) {
				log.info("加载JDBC驱动" + str_driver + "时非法访问,请检查配置文件");
			} catch (ClassNotFoundException e) {
				log.info("未找到JDBC驱动" + str_driver + "请引入相关包");
			} catch (SQLException e) {
				log.info("加载JDBC驱动" + str_driver + "失败,请检查引入包的正确性");
			}
			drivers.add(driver);
		}
	}

	/**
	 * 根据配置文件创建数据库连接池
	 */
	private void createPools() {
		Enumeration<?> elements = PropertiesMgr.propertiesNames();
		while(elements.hasMoreElements()) {
			String element = (String)elements.nextElement();
			if(element.endsWith(".url")) {
				String poolName = element.substring(0, element.lastIndexOf("."));
				String url = PropertiesMgr.getProperty(poolName + ".url");
				if(url == null) {
					log.error("无法连接到数据库" + poolName + "请检查配置文件连接字符串");
					continue;
				}
				String user = PropertiesMgr.getProperty(poolName + ".user");
				String pwd = PropertiesMgr.getProperty(poolName + ".password");
				String str_max = PropertiesMgr.getProperty(poolName + ".maxconn", "0");
				int maxConn = 0;
				try{
					maxConn = Integer.parseInt(str_max);
				}catch(NumberFormatException e) {
					log.error("数据库" + poolName + "最大连接数设置错误,默认设为20");
					maxConn = 20;
				}				
				DBConnectionPool pool = new DBConnectionPool(maxConn,url,poolName,user,pwd);
				pools.put(poolName, pool);
				log.info("成功创建数据库连接池" + poolName);
			}
		}
	}

	/**
	 * 获得单例
	 * @return DBConnectionManager单例
	 */
	public synchronized static DBConnectionManager getInstance() {
		if(dbm == null) {
			dbm = new DBConnectionManager();
		}
		clients++;
		return dbm;
	}

	/**
	 * 从指定连接池中获取可用连接,无等待
	 * @param poolName	要获取连接的连接池名称
	 * @return	连接池中的一个可用连接或null
	 */
	public Connection getConnection(String poolName) {
		DBConnectionPool pool = (DBConnectionPool)pools.get(poolName);
		return pool.getConnection();
	}
	
	/**
	 * 从指定的连接池获取可用连接,有等待超时
	 * @param poolName	要获取连接的连接池名称
	 * @param timeout	获取可用连接的超时时间,