日期:2014-05-16 浏览次数:20806 次
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 获取可用连接的超时时间,