Java 通用数据库连接类
package com.db; /** * 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接池的访问。 * 客户程序可以调用getInstance()方法访问本类的唯一实例。 * 装载和注册JDBC驱动程序。 * 根据在属性文件中定义的属性创建连接池对象。 * 实现连接池名字与其实例之间的映射。 * 跟踪客户程序对连接池的引用,保证在最后一个客户程序结束时安全地关闭所有连接池。 */ import java.io.*; import java.sql.*; import java.util.*; import java.util.Date; public class DBConnectionManager { static public DBConnectionManager instance; // 唯一实例 static public int clients; public Vector drivers = new Vector(); // 驱动 public PrintWriter log; // 日志 public Hashtable pools = new Hashtable(); // 连接 /** * 返回唯一实例.如果是第一次调用此方法,则创建实例 * * @return DBConnectionManager 唯一实例 */ static synchronized public DBConnectionManager getInstance() { if (instance == null) { instance = new DBConnectionManager(); } clients++; return instance; } /** * 建构函数私有以防止其它对象创建本类实例 */ public DBConnectionManager() { init(); } /** * 将连接对象返回给由名字指定的连接池 * * @param name * 在属性文件中定义的连接池名字 * @param con * 连接对象 */ public void freeConnection(String name, Connection con) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { pool.freeConnection(con); } else { System.out.println("pool ==null"); } clients--; } /** * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 限制,则创建并返回新连接 * * @param name * 在属性文件中定义的连接池名字 * @return Connection 可用连接或null */ public Connection getConnection(String name) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { // return pool.getConnection(); return pool.returnConnection(); } return null; } /** * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接. * * @param name * 连接池名字 * @param time * 以毫秒计的等待时间 * @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; } /** * 关闭所有连接,撤销驱动程序的注册 */ 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()); } } } /** * 读取属性完成初始化 */ private void init() { try { // Properties p = new Properties(); String configs = System.getProperty("user.dir") + "\\conf\\db.properties"; configs = Thread.currentThread().getContextClassLoader() .getResource("").toString(); configs = configs.replace("file:/", "") + "db.properties"; System.out.println("configs file local at " + configs); FileInputStream is = new FileInputStream(configs); 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"); logFile = dbProps.getProperty("logfile"); try { File f = new File(logFile); f = f.getParentFile(); if(f.mkdirs()){ log = new PrintWriter(new FileWriter(logFile, true), true); } } catch (IOException e) { System.err.println("无法打开日志文件: " + logFile); log = new PrintWriter(System.err); } loadDrivers(dbProps); createPools(dbProps); } catch (Exception e) { e.printStackTrace(); } } /** * 171 * 装载和注册所有JDBC驱动程序 172 * 173 * * * @param props * 属性 174 */ private void loadDrivers(Properties props) { Enumeration propNames = props.propertyNames(); while (propNames.hasMoreElements()) { String name = (String) propNames.nextElement(); if (name.endsWith(".driver")) { String poolName = name.substring(0, name.lastIndexOf(".")); String driverClasses = props.getProperty(poolName + ".driver"); 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); System.out.println(driverClassName); log("成功注册JDBC驱动程序" + driverClassName); } catch (Exception e) { log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e); } } } } // 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); // System.out.println(driverClassName); // log("成功注册JDBC驱动程序" + driverClassName); // } catch (Exception e) { // log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e); // } // } } /** * 根据指定属性创建连接池实例. * * @param props * 连接池属性 */ 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 log(String msg) { log.println(new Date() + ": " + msg); } /** * 将文本信息与异常写入日志文件 */ private void log(Throwable e, String msg) { log.println(new Date() + ": " + msg); e.printStackTrace(log); } /** * 类DBConnectionPool的作用: 从连接池获取(或创建)可用连接。 把连接返回给连接池 在系统关闭时释放所有资源,关闭所有连接。 * 处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题)。 限制连接池中的连接总数不超过某个预定值。 */ 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 * 此连接池允许建立的最大连接数,0表示没有限制 */ 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) { // 将指定连接加入到向量末尾 try { if (con.isClosed()) { System.out.println("before freeConnection con is closed"); } freeConnections.addElement(con); Connection contest = (Connection) freeConnections.lastElement(); if (contest.isClosed()) { System.out .println("after freeConnection contest is closed"); } notifyAll(); } catch (SQLException e) { System.out.println(e); } } /** * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之, * 然后递归调用自己以尝试新的可用连接. */ public synchronized Connection getConnection() { Connection con = null; if (freeConnections.size() > 0) { // 获取向量中第一个可用连接 con = (Connection) freeConnections.firstElement(); freeConnections.removeElementAt(0); try { if (con.isClosed()) { log("从连接池" + name + "删除一个无效连接"); System.out.println("从连接池" + name + "删除一个无效连接"); // 递归调用自己,尝试再次获取可用连接 con = getConnection(); } } catch (SQLException e) { log("从连接池" + name + "删除一个无效连接时错误"); System.out.println("从连接池" + name + "删除一个无效连接出错"); // 递归调用自己,尝试再次获取可用连接 con = getConnection(); } if (freeConnections.size() > maxConn) { System.out.println(" 删除一个溢出连接 "); releaseOne(); } } else if ((maxConn == 0) || (freeConnections.size() < maxConn)) { con = newConnection(); } return con; } public synchronized Connection returnConnection() { Connection con = null; // 如果闲置小于最大连接,返回一个新连接 if (freeConnections.size() < maxConn) { con = newConnection(); } // 如果闲置大于最大连接,返回一个可用的旧连接 else if (freeConnections.size() >= maxConn) { con = (Connection) freeConnections.firstElement(); System.out.println(" [a 连接池可用连接数 ] : " + "[ " + freeConnections.size() + " ]"); freeConnections.removeElementAt(0); System.out.println(" [b 连接池可用连接数 ] : " + "[ " + freeConnections.size() + " ]"); try { if (con.isClosed()) { log("从连接池" + name + "删除一个无效连接"); System.out.println("从连接池" + name + "删除一个无效连接"); returnConnection(); } } catch (SQLException e) { log("从连接池" + name + "删除一个无效连接时错误"); System.out.println("从连接池" + name + "删除一个无效连接出错"); returnConnection(); } } 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) { } 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 + "中的连接"); } } freeConnections.removeAllElements(); } /** * 关闭一个连接 */ public synchronized void releaseOne() { if (freeConnections.firstElement() != null) { Connection con = (Connection) freeConnections.firstElement(); try { con.close(); System.out.println("关闭连接池" + name + "中的一个连接"); log("关闭连接池" + name + "中的一个连接"); } catch (SQLException e) { System.out.println("无法关闭连接池" + name + "中的一个连接"); log(e, "无法关闭连接池" + name + "中的连接"); } } else { System.out .println("releaseOne() bug......................................................."); } } /** * 创建新的连接 */ private Connection newConnection() { Connection con = null; try { if (user == null) { con = DriverManager.getConnection(URL); } else { con = DriverManager.getConnection(URL, user, password); } log("连接池" + name + "创建一个新的连接"); } catch (SQLException e) { log(e, "无法创建下列URL的连接: " + URL); return null; } return con; } } }
package com.db; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import org.apache.log4j.Logger; /** * 数据库操作管理类 * * @author Harlyhood * */ public class DBManager { // --------------------------------------------------------- Instance private static Logger logger = Logger.getLogger(DBManager.class); // --------------------------------------------------------- Methods // 数据库连接对象 private Connection con; // SQL语句对象 private Statement stmt; // 带参数的Sql语句对象 private PreparedStatement pstmt; // 记录集对象 private ResultSet rs; // 数据连接管理(连接池对象) private DBConnectionManager dcm = null; /** ***********************手动设置的连接参数********************************* */ @SuppressWarnings("unused") private static String _DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; @SuppressWarnings("unused") private static String _URL = "jdbc:sqlserver://localhost:1433;database=Hospital_AI_DB;characterEncoding=gb2312"; @SuppressWarnings("unused") private static String _USER_NA = "sa"; @SuppressWarnings("unused") private static String _PASSWORD = ""; /** ********************************************************************** */ // 默认构造 public DBManager() { } /** ****************************************************************************************** */ /** * **************************************** 数据库连接初始化 * *********************************** */ /** ****************************************************************************************** */ /** * 得到一个默认的数据库连接[从 com.hospital.dao.tools.db.properties文件初始化] * * @throws Exception */ private void getConnection() { logger.info("###############open:::::从默认的配置文件得到一个数据库连接"); // 获取一个连接池管理类的实例 dcm = DBConnectionManager.getInstance(); // 得到一个数据库连接 con = dcm.getConnection("mysql"); try { con.setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } } /** * 从指定参数得到一个连接对象 * * @param driver * @param url * @param user_na * @param password * @throws Exception */ public void getConnection(String driver, String url, String user_na, String password) throws Exception { try { logger.info("###############open:::::从指定配置中得到一个数据库连接"); Class.forName(driver); con = DriverManager.getConnection(url, user_na, password); } catch (ClassNotFoundException ex) { logger .info("###############Error[com.hospital.dao.tools.DBManager^^^Method:getConnection^^^Line:81]找不到类驱动类: " + driver); throw ex; } catch (SQLException ex) { logger .info("###############Error[com.hospital.dao.tools.DBManager^^^Method:getConnection^^^Line:81]加载类: " + driver + " 时出现 SQLException 异常"); throw ex; } } /** ****************************************************************************************** */ /** * **************************************** 数据库操作方法 * *********************************** */ /** ****************************************************************************************** */ /** * 执行SQL语句操作(更新数据 无参数) * * @param strSql * SQL语句 * @throws Exception */ public boolean executeUpdate(String strSql) throws SQLException { getConnection(); // getConnection(_DRIVER,_URL,_USER_NA,_PASSWORD); boolean flag = false; stmt = con.createStatement(); logger.info("###############::执行SQL语句操作(更新数据 无参数):" + strSql); try { if (0 < stmt.executeUpdate(strSql)) { close_DB_Object(); flag = true; con.commit(); } } catch (SQLException ex) { logger .info("###############Error DBManager Line126::执行SQL语句操作(更新数据 无参数):" + strSql + "失败!"); flag = false; con.rollback(); throw ex; } return flag; } /** * 执行SQL语句操作(更新数据 有参数) * * @param strSql * sql指令 * @param prams * 参数列表 * @return * @throws SQLException */ public boolean executeUpdate(String strSql, HashMap<Integer, Object> prams) throws SQLException, ClassNotFoundException { getConnection(); // getConnection(_DRIVER,_URL,_USER_NA,_PASSWORD); boolean flag = false; try { pstmt = con.prepareStatement(strSql); setParamet(pstmt, prams); logger.info("###############::执行SQL语句操作(更新数据 有参数):" + strSql); if (0 < pstmt.executeUpdate()) { close_DB_Object(); flag = true; con.commit(); } } catch (SQLException ex) { logger .info("###############Error DBManager Line121::执行SQL语句操作(更新数据 无参数):" + strSql + "失败!"); flag = false; con.rollback(); throw ex; } catch (ClassNotFoundException ex) { logger .info("###############Error DBManager Line152::执行SQL语句操作(更新数据 无参数):" + strSql + "失败! 参数设置类型错误!"); con.rollback(); throw ex; } return flag; } /** * 执行SQL语句操作(查询数据 无参数) * * @param strSql * SQL语句 * @return 数组对象列表 * @throws Exception */ public ArrayList<HashMap<Object, Object>> executeSql(String strSql) throws Exception { getConnection(); // getConnection(_DRIVER,_URL,_USER_NA,_PASSWORD); stmt = con.createStatement(); logger.info("###############::执行SQL语句操作(查询数据):" + strSql); rs = stmt.executeQuery(strSql); con.commit(); if (null != rs) { return convertResultSetToArrayList(rs); } close_DB_Object(); return null; } /** * 执行SQL语句操作(查询数据 有参数) * * @param strSql * SQL语句 * @param prams * 参数列表 * @return 数组对象列表 * @throws Exception */ public ArrayList<HashMap<Object, Object>> executeSql(String strSql, HashMap<Integer, Object> prams) throws Exception { getConnection(); // getConnection(_DRIVER,_URL,_USER_NA,_PASSWORD); pstmt = con.prepareStatement(strSql); setParamet(pstmt, prams); logger.info("###############::执行SQL语句操作(查询数据):" + strSql); rs = pstmt.executeQuery(); con.commit(); if (null != rs) { return convertResultSetToArrayList(rs); } return null; } /** * 执行存储过程(查询数据 无参数) * * @param procName * 存储过程名称 * @return 数组列表对象 * @throws Exception */ public ArrayList<HashMap<Object, Object>> executeProcedureQuery( String procName) throws Exception { getConnection();// 获取连接 String callStr = "{call " + procName + "}";// 构造执行存储过程的sql指令 CallableStatement cs = con.prepareCall(callStr); logger.info("###############::执行存储过程(查询数据):" + procName); rs = cs.executeQuery(); con.commit(); cs.close(); close_DB_Object(); return convertResultSetToArrayList(rs); } /** * 执行存储过程(查询数据,带参数)返回结果集合 * * @param procName * 存储过程名称 * @param parameters * 参数对象数组 * @param al * 数组列表对象 * @return 数组列表对象 * @throws Exception */ public ArrayList<HashMap<Object, Object>> executeProcedureQuery( String procName, Object[] parameters) throws Exception { int parameterPoint = 0; // 获取存储过程信息列表集合 ArrayList<HashMap<Object, Object>> procedureInfo = getProcedureInfo(procName); // 获取存储过程的完全名称 String procedureCallName = getProcedureCallName(procName,parameters.length); // 获取连接对象 getConnection(); // 初始化 存储过程 执行对象 CallableStatement cs = con.prepareCall(procedureCallName); // 参数下标变量 int index = 0; // 获取 存储过程信息列表集合的 迭代器 对象 Iterator<HashMap<Object, Object>> iter = procedureInfo.iterator(); // 遍历存储过程信息列表集合 while (iter.hasNext()) { HashMap<Object, Object> hm = iter.next(); parameterPoint++; // 如果参数是输入参数 way = 0 if (hm.get("WAY").equals("0")) { // 设置参数到cs cs.setObject(parameterPoint, parameters[index]); // 参数下标+1 index++; } } // 释放这个对象,做为第二次使用 procedureInfo = null; logger.info("###############::执行存储过程(查询数据):::::" + procedureCallName); rs = cs.executeQuery(); con.commit(); procedureInfo = convertResultSetToArrayList(rs); cs.close(); close_DB_Object(); return procedureInfo; } /** * 执行存储过程(更新,查询数据[简单查询、非纪录集],返回输出参数[非纪录集]) * * @param procName * 存储过程名称 * @param parameters * 参数对象数组 * @param os * 输出参数对象数组 * @return 输出参数对象数组 * @throws Exception */ public Object[] executeProcedureUpdate(String procName, Object[] parameters) throws Exception { logger.info("------------------------------------------------------------------------------------------------------"); logger.info(" Run --> executeProcedureUpdate ############## 正在执行 存储过程: " + procName +" ##############"); CallableStatement cs = null; Object []returnVal = null; try { // 获取 存储过程 调用全名 String fullPCallName = getProcedureCallName(procName,parameters.length); logger.info(" Run --> executeProcedureUpdate # 存储过程命令: " + fullPCallName +" #"); //获取存储过程参数信息 ArrayList<HashMap<Object, Object>> p_Call_Info_List = getProcedureInfo(procName); //获取连接 getConnection(); //创建 存储过程 执行对象 cs = con.prepareCall(fullPCallName); //数组下标 int index = 1; //输出参数下标 纪录 ArrayList<Integer> outPutIndexList = new ArrayList<Integer>(); logger.info(" Run --> executeProcedureUpdate # 参数个数是: " + parameters.length +" #"); for(HashMap<Object,Object> tempHash:p_Call_Info_List) { if("0".equals(tempHash.get("WAY"))) { //设置输入参数 cs.setObject(index, parameters[index-1]); logger.info(" Run --> executeProcedureUpdate # 输入 Input: 编号:" + index +" 值: "+parameters[index-1]+" 类型: "+parameters[index-1].getClass()+" #"); } else { //注册输出参数 cs.registerOutParameter(index, getDataType(tempHash.get("TYPENAME").toString())); //纪录输出参数的下标 outPutIndexList.add(index); logger.info(" Run --> executeProcedureUpdate # 输出 OutPut: 编号:" + index +" 值: "+parameters[index-1]+" 类型: "+parameters[index-1].getClass()+" #"); } index++; } logger.info(" Run --> executeProcedureUpdate # 参数设置完毕,正在执行中 ... : #"); //-------------------- 执行 ----------------- if(!cs.execute()) { returnVal = new Object[outPutIndexList.size()]; logger.info(" Run --> executeProcedureUpdate # 执行成功! : #"); //取输 出参数的 返回值 for(int i = 0 ;i<outPutIndexList.size();i++) { returnVal[i] = cs.getObject(outPutIndexList.get(i)); logger.info(" Run --> executeProcedureUpdate # 返回值 "+(i+1)+" "+returnVal[i]+" #"); } con.commit();//提交 } } catch (Exception e) { logger.info(" Run --> executeProcedureUpdate # 执行失败!事务回滚中... : #"); con.rollback(); throw e; } logger.info("------------------------------------------------------------------------------------------------------"); return returnVal; } /** ****************************************************************************************** */ /** * ********************************* 小工具 * ************************************************ */ /** ****************************************************************************************** */ /** * 关闭数据对象 */ public void close_DB_Object() { logger.info("###############close:::::关闭连接对象,语句对象,记录集对象"); if (null != rs) { try { rs.close(); } catch (SQLException ex) { rs = null; } } if (null != stmt) { try { stmt.close(); } catch (SQLException ex) { stmt = null; } } if (null != pstmt) { try { pstmt.close(); } catch (SQLException ex) { pstmt = null; } } if (con != null) { dcm.freeConnection("mysql", con); } } /** * 设置Sql 指令参数 * * @param p_stmt * PreparedStatement * @param pramets * HashMap */ private PreparedStatement setParamet(PreparedStatement p_stmt, HashMap<Integer, Object> pramets) throws ClassNotFoundException, SQLException { // 如果参数为空 if (null != pramets) { // 如果参数个数为0 if (0 <= pramets.size()) { for (int i = 1; i <= pramets.size(); i++) { try { // 字符类型 String if (pramets.get(i).getClass() == Class .forName("java.lang.String")) { p_stmt.setString(i, pramets.get(i).toString()); } // 日期类型 Date if (pramets.get(i).getClass() == Class .forName("java.sql.Date")) { p_stmt.setDate(i, java.sql.Date.valueOf(pramets .get(i).toString())); } // 布尔类型 Boolean if (pramets.get(i).getClass() == Class .forName("java.lang.Boolean")) { p_stmt.setBoolean(i, (Boolean) (pramets.get(i))); } // 整型 int if (pramets.get(i).getClass() == Class .forName("java.lang.Integer")) { p_stmt.setInt(i, (Integer) pramets.get(i)); } // 浮点 float if (pramets.get(i).getClass() == Class .forName("java.lang.Float")) { p_stmt.setFloat(i, (Float) pramets.get(i)); } // 双精度型 double if (pramets.get(i).getClass() == Class .forName("java.lang.Double")) { p_stmt.setDouble(i, (Double) pramets.get(i)); } } catch (ClassNotFoundException ex) { throw ex; } catch (SQLException ex) { throw ex; } } } } return p_stmt; } /** * 转换记录集对象为数组列表对象 * * @param rs * 纪录集合对象 * @return 数组列表对象 * @throws Exception */ private ArrayList<HashMap<Object, Object>> convertResultSetToArrayList( ResultSet rs) throws Exception { logger.info("###############::转换记录集对象为数组列表对象"); // 获取rs 集合信息对象 ResultSetMetaData rsmd = rs.getMetaData(); // 创建数组列表集合对象 ArrayList<HashMap<Object, Object>> tempList = new ArrayList<HashMap<Object, Object>>(); HashMap<Object, Object> tempHash = null; // 填充数组列表集合 while (rs.next()) { // 创建键值对集合对象 tempHash = new HashMap<Object, Object>(); for (int i = 0; i < rsmd.getColumnCount(); i++) { // 遍历每列数据,以键值形式存在对象tempHash中 tempHash.put(rsmd.getColumnName(i + 1).toUpperCase(), rs .getString(rsmd.getColumnName(i + 1))); } // 第一个键值对,存储在tempList列表集合对象中 tempList.add(tempHash); } close_DB_Object();// 关闭相关链接 return tempList;// 返回填充完毕的数组列表集合对象 } /** * 从数据库得到存储过程信息 * * @param procName * 存储过程名称 * @return 数组列表对象 * @throws Exception */ private ArrayList<HashMap<Object, Object>> getProcedureInfo(String procName) throws Exception { return this.executeSql("select Syscolumns.isoutparam as Way,systypes.name as TypeName from sysobjects,syscolumns,systypes where systypes.xtype=syscolumns.xtype and syscolumns.id=sysobjects.id and sysobjects.name='" + procName + "' order by Syscolumns.isoutparam"); } /** * 从数据库得到存储过程参数个数 * * @param procName * 存储过程名称 * @return 数组列表对象 * @throws Exception */ @SuppressWarnings("unused") private int getParametersCount(String procName) throws Exception { int returnVal = 0; for (HashMap<Object, Object> tempHas : this .executeSql("select count(*) as RowsCount from sysobjects,syscolumns,systypes where systypes.xtype=syscolumns.xtype and syscolumns.id=sysobjects.id and sysobjects.name='" + procName + "'")) { returnVal = Integer.parseInt(tempHas.get("ROWSCOUNT").toString()); } return returnVal; } /** * 得到调用存储过程的全名 * * @param procName * 存储过程名称 * @return 调用存储过程的全名 * @throws Exception */ private String getProcedureCallName(String procName, int prametCount) throws Exception { String procedureCallName = "{call " + procName; for (int i = 0; i < prametCount; i++) { if (0 == i) { procedureCallName = procedureCallName + "(?"; } if (0 != i) { procedureCallName = procedureCallName + ",?"; } } procedureCallName = procedureCallName + ")}"; return procedureCallName; } /** * 得到数据类型的整型值 * * @param typeName * 类型名称 * @return 数据类型的整型值 */ private int getDataType(String typeName) { if (typeName.equals("varchar")) return Types.VARCHAR; if (typeName.equals("int")) return Types.INTEGER; if (typeName.equals("bit")) return Types.BIT; if (typeName.equals("float")) return Types.FLOAT; return 0; } // 设置驱动路径 @SuppressWarnings("static-access") public void set_DRIVER(String _DRIVER) { this._DRIVER = _DRIVER; } // 设置数据库密码 @SuppressWarnings("static-access") public void set_PASSWORD(String _PASSWORD) { this._PASSWORD = _PASSWORD; } // 设置数据库连接字符串 @SuppressWarnings("static-access") public void set_URL(String _URL) { this._URL = _URL; } // 设置数据库用户名 @SuppressWarnings("static-access") public void set_USER_NA(String _USER_NA) { this._USER_NA = _USER_NA; } }
package com.db; /** * 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接池的访问。 * 客户程序可以调用getInstance()方法访问本类的唯一实例。 * 装载和注册JDBC驱动程序。 * 根据在属性文件中定义的属性创建连接池对象。 * 实现连接池名字与其实例之间的映射。 * 跟踪客户程序对连接池的引用,保证在最后一个客户程序结束时安全地关闭所有连接池。 */ import java.io.*; import java.sql.*; import java.util.*; import java.util.Date; public class DBConnectionManager { static public DBConnectionManager instance; // 唯一实例 static public int clients; public Vector drivers = new Vector(); // 驱动 public PrintWriter log; // 日志 public Hashtable pools = new Hashtable(); // 连接 /** * 返回唯一实例.如果是第一次调用此方法,则创建实例 * * @return DBConnectionManager 唯一实例 */ static synchronized public DBConnectionManager getInstance() { if (instance == null) { instance = new DBConnectionManager(); } clients++; return instance; } /** * 建构函数私有以防止其它对象创建本类实例 */ public DBConnectionManager() { init(); } /** * 将连接对象返回给由名字指定的连接池 * * @param name * 在属性文件中定义的连接池名字 * @param con * 连接对象 */ public void freeConnection(String name, Connection con) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { pool.freeConnection(con); } else { System.out.println("pool ==null"); } clients--; } /** * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 限制,则创建并返回新连接 * * @param name * 在属性文件中定义的连接池名字 * @return Connection 可用连接或null */ public Connection getConnection(String name) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { // return pool.getConnection(); return pool.returnConnection(); } return null; } /** * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接. * * @param name * 连接池名字 * @param time * 以毫秒计的等待时间 * @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; } /** * 关闭所有连接,撤销驱动程序的注册 */ 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 * 连接池属性 */ 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() { try { // Properties p = new Properties(); String configs = System.getProperty("user.dir") + "\\conf\\db.properties"; System.out.println("configs file local at " + configs); FileInputStream is = new FileInputStream(configs); 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); } catch (Exception e) { } } /** * 171 * 装载和注册所有JDBC驱动程序 172 * 173 * * * @param props * 属性 174 */ 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); System.out.println(driverClassName); log("成功注册JDBC驱动程序" + driverClassName); } catch (Exception e) { 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的作用: 从连接池获取(或创建)可用连接。 把连接返回给连接池 在系统关闭时释放所有资源,关闭所有连接。 * 处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题)。 限制连接池中的连接总数不超过某个预定值。 */ 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 * 此连接池允许建立的最大连接数,0表示没有限制 */ 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) { // 将指定连接加入到向量末尾 try { if (con.isClosed()) { System.out.println("before freeConnection con is closed"); } freeConnections.addElement(con); Connection contest = (Connection) freeConnections.lastElement(); if (contest.isClosed()) { System.out.println("after freeConnection contest is closed"); } notifyAll(); } catch (SQLException e) { System.out.println(e); } } /** * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之, * 然后递归调用自己以尝试新的可用连接. */ public synchronized Connection getConnection() { Connection con = null; if (freeConnections.size() > 0) { // 获取向量中第一个可用连接 con = (Connection) freeConnections.firstElement(); freeConnections.removeElementAt(0); try { if (con.isClosed()) { log("从连接池" + name + "删除一个无效连接"); System.out.println("从连接池" + name + "删除一个无效连接"); // 递归调用自己,尝试再次获取可用连接 con = getConnection(); } } catch (SQLException e) { log("从连接池" + name + "删除一个无效连接时错误"); System.out.println("从连接池" + name + "删除一个无效连接出错"); // 递归调用自己,尝试再次获取可用连接 con = getConnection(); } if (freeConnections.size() > maxConn) { System.out.println(" 删除一个溢出连接 "); releaseOne(); } } else if ((maxConn == 0) || (freeConnections.size() < maxConn)) { con = newConnection(); } return con; } public synchronized Connection returnConnection() { Connection con = null; // 如果闲置小于最大连接,返回一个新连接 if (freeConnections.size() < maxConn) { con = newConnection(); } // 如果闲置大于最大连接,返回一个可用的旧连接 else if (freeConnections.size() >= maxConn) { con = (Connection) freeConnections.firstElement(); System.out.println(" [a 连接池可用连接数 ] : " + "[ " + freeConnections.size() + " ]"); freeConnections.removeElementAt(0); System.out.println(" [b 连接池可用连接数 ] : " + "[ " + freeConnections.size() + " ]"); try { if (con.isClosed()) { log("从连接池" + name + "删除一个无效连接"); System.out.println("从连接池" + name + "删除一个无效连接"); returnConnection(); } } catch (SQLException e) { log("从连接池" + name + "删除一个无效连接时错误"); System.out.println("从连接池" + name + "删除一个无效连接出错"); returnConnection(); } } 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) { } 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 + "中的连接"); } } freeConnections.removeAllElements(); } /** * 关闭一个连接 */ public synchronized void releaseOne() { if (freeConnections.firstElement() != null) { Connection con = (Connection) freeConnections.firstElement(); try { con.close(); System.out.println("关闭连接池" + name + "中的一个连接"); log("关闭连接池" + name + "中的一个连接"); } catch (SQLException e) { System.out.println("无法关闭连接池" + name + "中的一个连接"); log(e, "无法关闭连接池" + name + "中的连接"); } } else { System.out .println("releaseOne() bug......................................................."); } } /** * 创建新的连接 */ private Connection newConnection() { Connection con = null; try { if (user == null) { con = DriverManager.getConnection(URL); } else { con = DriverManager.getConnection(URL, user, password); } log("连接池" + name + "创建一个新的连接"); } catch (SQLException e) { log(e, "无法创建下列URL的连接: " + URL); return null; } return con; } } }