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; } } }
原文地址:https://www.cnblogs.com/xsmhero/p/2913228.html