JDBC Connection Pool Example

    技术2022-05-11  104

     

    /* * Copyright (c) 1998 by Gefion software. * * Permission to use, copy, and distribute this software for * NON-COMMERCIAL purposes and without fee is hereby granted * provided that this copyright notice appears in all copies. * */

    import java.io.*;import java.sql.*;import java.util.*;import java.util.Date;

    /** * This class is a Singleton that provides access to one or many * connection pools defined in a Property file. A client gets * access to the single instance through the static getInstance() * method and can then check-out and check-in connections from a pool. * When the client shuts down it should call the release() method * to close all open connections and do other clean up. */public class DBConnectionManager {    static private DBConnectionManager instance;       // The single instance    static private int clients;

        private Vector drivers = new Vector();    private PrintWriter log;    private Hashtable pools = new Hashtable();        /**     * Returns the single instance, creating one if it's the     * first time this method is called.     *     * @return DBConnectionManager The single instance.     */    static synchronized public DBConnectionManager getInstance() {        if (instance == null) {            instance = new DBConnectionManager();        }        clients++;        return instance;    }        /**     * A private constructor since this is a Singleton     */    private DBConnectionManager() {        init();    }        /**     * Returns a connection to the named pool.     *     * @param name The pool name as defined in the properties file     * @param con The Connection     */    public void freeConnection(String name, Connection con) {        DBConnectionPool pool = (DBConnectionPool) pools.get(name);        if (pool != null) {            pool.freeConnection(con);        }    }            /**     * Returns an open connection. If no one is available, and the max     * number of connections has not been reached, a new connection is     * created.     *     * @param name The pool name as defined in the properties file     * @return Connection The connection or null     */    public java.sql.Connection getConnection(String name) {        DBConnectionPool pool = (DBConnectionPool) pools.get(name);        if (pool != null) {            return pool.getConnection();        }        return null;    }        /**     * Returns an open connection. If no one is available, and the max     * number of connections has not been reached, a new connection is     * created. If the max number has been reached, waits until one     * is available or the specified time has elapsed.     *     * @param name The pool name as defined in the properties file     * @param time The number of milliseconds to wait     * @return Connection The connection or null     */    public java.sql.Connection getConnection(String name, long time) {        DBConnectionPool pool = (DBConnectionPool) pools.get(name);        if (pool != null) {            return pool.getConnection(time);        }        return null;    }        /**     * Closes all open connections and deregisters all drivers.     */    public synchronized void release() {        // Wait until called by the last client        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("Deregistered JDBC driver " + driver.getClass().getName());            }            catch (SQLException e) {                log(e, "Can't deregister JDBC driver: " + driver.getClass().getName());            }        }    }        /**     * Creates instances of DBConnectionPool based on the properties.     * A DBConnectionPool can be defined with the following properties:     * <PRE>     * <poolname>.url         The JDBC URL for the database     * <poolname>.user        A database user (optional)     * <poolname>.password    A database user password (if user specified)     * <poolname>.maxconn     The maximal number of connections (optional)     * </PRE>     *     * @param props The connection pool 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("No URL specified for " + poolName);                    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("Invalid maxconn value " + maxconn + " for " + poolName);                    max = 0;                }                DBConnectionPool pool =                     new DBConnectionPool(poolName, url, user, password, max);                pools.put(poolName, pool);                log("Initialized pool " + poolName);            }        }    }        /**     * Loads properties and initializes the instance with its values.     */    private void init() {        InputStream is = getClass().getResourceAsStream("/db.properties");        Properties dbProps = new Properties();        try {            dbProps.load(is);        }        catch (Exception e) {            System.err.println("Can't read the properties file. " +                "Make sure db.properties is in the CLASSPATH");            return;        }        String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log");        try {            log = new PrintWriter(new FileWriter(logFile, true), true);        }        catch (IOException e) {            System.err.println("Can't open the log file: " + logFile);            log = new PrintWriter(System.err);        }        loadDrivers(dbProps);        createPools(dbProps);    }        /**     * Loads and registers all JDBC drivers. This is done by the     * DBConnectionManager, as opposed to the DBConnectionPool,     * since many pools may share the same driver.     *     * @param props The connection pool 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("Registered JDBC driver " + driverClassName);            }            catch (Exception e) {                log("Can't register JDBC driver: " +                    driverClassName + ", Exception: " + e);            }        }    }        /**     * Writes a message to the log file.     */    private void log(String msg) {        log.println(new Date() + ": " + msg);    }        /**     * Writes a message with an Exception to the log file.     */    private void log(Throwable e, String msg) {        log.println(new Date() + ": " + msg);        e.printStackTrace(log);    }        /**     * This inner class represents a connection pool. It creates new     * connections on demand, up to a max number if specified.     * It also makes sure a connection is still open before it is     * returned to a client.     */    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;                /**         * Creates new connection pool.         *         * @param name The pool name         * @param URL The JDBC URL for the database         * @param user The database user, or null         * @param password The database user password, or null         * @param maxConn The maximal number of connections, or 0         *   for no limit         */        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;        }                /**         * Checks in a connection to the pool. Notify other Threads that         * may be waiting for a connection.         *         * @param con The connection to check in         */        public synchronized void freeConnection(Connection con) {            // Put the connection at the end of the Vector            freeConnections.addElement(con);            checkedOut--;            notifyAll();        }                /**         * Checks out a connection from the pool. If no free connection         * is available, a new connection is created unless the max         * number of connections has been reached. If a free connection         * has been closed by the database, it's removed from the pool         * and this method is called again recursively.         */        public synchronized java.sql.Connection getConnection() {            java.sql.Connection con = null;            if (freeConnections.size() > 0) {                // Pick the first Connection in the Vector                // to get round-robin usage                con = (java.sql.Connection) freeConnections.firstElement();                freeConnections.removeElementAt(0);                try {                    if (con.isClosed()) {                        log("Removed bad connection from " + name);                        // Try again recursively                        con = getConnection();                    }                }                catch (SQLException e) {                    log("Removed bad connection from " + name);                    // Try again recursively                    con = getConnection();                }            }            else if (maxConn == 0 || checkedOut < maxConn) {                con = newConnection();            }            if (con != null) {                checkedOut++;            }            return con;        }                /**         * Checks out a connection from the pool. If no free connection         * is available, a new connection is created unless the max         * number of connections has been reached. If a free connection         * has been closed by the database, it's removed from the pool         * and this method is called again recursively.         * <P>         * If no connection is available and the max number has been          * reached, this method waits the specified time for one to be         * checked in.         *         * @param timeout The timeout value in milliseconds         */        public synchronized java.sql.Connection getConnection(long timeout) {            long startTime = new Date().getTime();            java.sql.Connection con;            while ((con = getConnection()) == null) {                try {                    wait(timeout);                }                catch (InterruptedException e) {}                if ((new Date().getTime() - startTime) >= timeout) {                    // Timeout has expired                    return null;                }            }            return con;        }                /**         * Closes all available connections.         */        public synchronized void release() {            Enumeration allConnections = freeConnections.elements();            while (allConnections.hasMoreElements()) {                java.sql.Connection con = (java.sql.Connection) allConnections.nextElement();                try {                    con.close();                    log("Closed connection for pool " + name);                }                catch (SQLException e) {                    log(e, "Can't close connection for pool " + name);                }            }            freeConnections.removeAllElements();        }                /**         * Creates a new connection, using a userid and password         * if specified.         */        private java.sql.Connection newConnection() {            java.sql.Connection con = null;            try {                if (user == null) {                    con = DriverManager.getConnection(URL);                }                else {                    con = DriverManager.getConnection(URL, user, password);                }                log("Created a new connection in pool " + name);            }            catch (SQLException e) {                log(e, "Can't create a new connection for " + URL);                return null;            }            return con;        }    }}


    最新回复(0)