返回目录
一个连接池的例子
  作者:未知 更新人:Legume 来源:未知 更新时间:2004.08.24  投稿信箱: tg*ddvip.com


//文件:DbConnectionDefaultPool.java的第一部分

//请注意看里面注明的一处需要修改连接参数的地方
package com.qingtuo.db.pool;

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


/**
* Default Jive connection provider. It uses the excellent connection pool
* available from http://www.javaexchange.com. This connection provider is a
* a good choice unless you can use a container-managed one.
*/
public class DbConnectionDefaultPool extends DbConnectionProvider {

    private static final String NAME = "Default Connection Pool";
    private static final String DESCRIPTION = "The default connection provider "
        + "that uses the connection pool from javaexchange.com. It works with "
        + "almost any database setup, is customizable, and offers good performance. "
        + "Use this connection provider unless you have your own or can use a "
        + "container managed connection pool.";
    private static final String AUTHOR = "CoolServlets.com";
    private static final int MAJOR_VERSION = 1;
    private static final int MINOR_VERSION = 0;
    private static final boolean POOLED = true;

    private ConnectionPool connectionPool = null;
    private Properties props;
    private Properties propDescriptions;

    private Object initLock = new Object();

    public DbConnectionDefaultPool() {
        //this.manager = manager;
        props = new Properties();
        propDescriptions = new Properties();
        //Initialize all property values
        initializeProperties();
        //Load any existing property values
        loadProperties();
    }

    /**
     * Returns a database connection.
     */
    public Connection getConnection() {
        if (connectionPool == null) {
            //block until the init has been done
            synchronized(initLock) {
                //if still null, something has gone wrong
                if (connectionPool == null) {
                    System.err.println("Warning: DbConnectionDefaultPool.getConnection() was " +
                    "called when the internal pool has not been initialized.");
                    return null;
                }
            }
        }
        return new ConnectionWrapper(connectionPool.getConnection(), connectionPool);
    }

    /**
     * Starts the pool.
     */
    protected void start() {
        //acquire lock so that no connections can be returned.
        synchronized (initLock) {
            //Get properties
            String driver = props.getProperty("driver");
            String server = props.getProperty("server");
            String username = props.getProperty("username");
            String password = props.getProperty("password");
            int minConnections = 0, maxConnections = 0;
            double connectionTimeout = 0.0;
            try {
                minConnections = Integer.parseInt(props.getProperty("minConnections"));
                maxConnections = Integer.parseInt(props.getProperty("maxConnections"));
                connectionTimeout = Double.parseDouble(props.getProperty("connectionTimeout"));
            }
            catch (Exception e) {
                System.err.println("Error: could not parse default pool properties. " +
                    "Make sure the values exist and are correct.");
                e.printStackTrace();
                return;
            }
            String logPath = props.getProperty("logPath");

            try {
                connectionPool = new ConnectionPool(driver, server, username, password,
                    minConnections, maxConnections, logPath, connectionTimeout);
            }
            catch (IOException ioe) {
                System.err.println("Error starting DbConnectionDefaultPool: " + ioe);
                ioe.printStackTrace();
            }
        }
    }

    /**
     * Restarts the pool to take into account any property changes.
     */
    protected void restart() {
        //Kill off pool.
        destroy();
        //Reload properties.
        loadProperties();
        //Start a new pool.
        start();
    }

    /**
     * Destroys the connection pool.
     */
    protected void destroy() {
        if (connectionPool != null) {
            try {
                connectionPool.destroy(1);
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        //Release reference to connectionPool
        connectionPool = null;
    }

    /**
     * Returns the value of a property of the connection provider.
     *
     * @param name the name of the property.
     * @returns the value of the property.
     */
    public String getProperty(String name) {
        return (String)props.get(name);
    }

    /**
     * Returns the description of a property of the connection provider.
     *
     * @param name the name of the property.
     * @return the description of the property.
     */
    public String getPropertyDescription(String name) {
        return (String)propDescriptions.get(name);
    }

    /**
     * Returns an enumeration of the property names for the connection provider.
     */
    public Enumeration propertyNames() {
        return props.propertyNames();
    }

    /**
     * Sets a property of the connection provider. Each provider has a set number
     * of properties that are determined by the author. Trying to set a non-
     * existant property will result in an IllegalArgumentException.
     *
     * @param name the name of the property to set.
     * @param value the new value for the property.
     *
     */
    public void setProperty(String name, String value) {
        props.put(name, value);
        saveProperties();
    }

    /**
     * Give default values to all the properties and descriptions.
     */
    private void initializeProperties() {
        props.put("driver","");
        props.put("server","");
        props.put("username","");
        props.put("password","");
        props.put("minConnections","");
        props.put("maxConnections","");
        props.put("logPath","");
        props.put("connectionTimeout","");

        propDescriptions.put("driver","JDBC driver. e.g. 'oracle.jdbc.driver.OracleDriver'");
        propDescriptions.put("server","JDBC connect string. e.g. 'jdbc:oracle:thin:@203.92.21.109:1526:orcl'");
        propDescriptions.put("username","Database username. e.g. 'Scott'");
        propDescriptions.put("password","Database password. e.g. 'Tiger'");
        propDescriptions.put("minConnections","Minimum # of connections to start with in pool. Three is the recommended minimum");
        propDescriptions.put("maxConnections","Maximum # of connections in dynamic pool. Fifteen should give good performance for an average load.");
        propDescriptions.put("logPath","Absolute path name for log file. e.g. 'c:\\logs\\jiveDbLog.log'");
        propDescriptions.put("connectionTimeout","Time in days between connection resets. e.g. '.5'");
    }

    /**
     * Load whatever properties that already exist.
     */
    private void loadProperties() {
        //在这里修改一些连接参数
        //in 2000
        /*
        String driver="org.gjt.mm.mysql.Driver";
        String server="jdbc:mysql://192.100.100.11/pcc";
        String username="pcc";
        String password="pcc123";
        String minConnections="3";
        String maxConnections="10";
        String logPath="c:\\temp\\qingtuoDbLog.log";
        String connectionTimeout="0.5";
        */
        //in Linux
        
        String driver="org.gjt.mm.mysql.Driver";
        String server="jdbc:mysql://192.100.100.1/qingtuo";
        //String server="jdbc:mysql://192.168.0.1/qingtuo";
        String username="qingtuo";
        String password="qingtuo";
        String minConnections="3";
        String maxConnections="20";
        String logPath="c:\\temp\\qingtuoDbLog.log";
//        String logPath="/tmp/qingtuoDbLog.log";
        String connectionTimeout="0.5";
        
        
        if (driver != null) {  props.setProperty("driver", driver);  }
        if (server != null) {  props.setProperty("server", server);  }
        if (username != null) {  props.setProperty("username", username);  }
        if (password != null) {  props.setProperty("password", password);  }
        //if (database != null) {  props.setProperty("database", database);  }
        if (minConnections != null) {  props.setProperty("minConnections", minConnections);  }
        if (maxConnections != null) {  props.setProperty("maxConnections", maxConnections);  }
        if (logPath != null) {  props.setProperty("logPath", logPath);  }
        if (connectionTimeout != null) {  props.setProperty("connectionTimeout", connectionTimeout);  }
    }

    private void saveProperties() {
        PropertyManager.setProperty("DbConnectionDefaultPool.driver", props.getProperty("driver"));
        PropertyManager.setProperty("DbConnectionDefaultPool.server", props.getProperty("server"));
        PropertyManager.setProperty("DbConnectionDefaultPool.username", props.getProperty("username"));
        PropertyManager.setProperty("DbConnectionDefaultPool.password", props.getProperty("password"));
        PropertyManager.setProperty("DbConnectionDefaultPool.minConnections", props.getProperty("minConnections"));
        PropertyManager.setProperty("DbConnectionDefaultPool.maxConnections", props.getProperty("maxConnections"));
        PropertyManager.setProperty("DbConnectionDefaultPool.logPath", props.getProperty("logPath"));
        PropertyManager.setProperty("DbConnectionDefaultPool.connectionTimeout", props.getProperty("connectionTimeout"));
    }

    private class ConnectionPool implements Runnable {
        private Thread runner;
    
        private Connection[] connPool;
        private int[] connStatus;

        private long[] connLockTime, connCreateDate;
        private String[] connID;
        private String dbDriver, dbServer, dbLogin, dbPassword, logFileString;
        private int currConnections, connLast, minConns, maxConns, maxConnMSec;

        //available: set to false on destroy, checked by getConnection()
        private boolean available=true;

        private PrintWriter log;
        private SQLWarning currSQLWarning;
        private String pid;

        /**
         * Creates a new Connection Broker<br>
         * dbDriver:        JDBC driver. e.g. 'oracle.jdbc.driver.OracleDriver'<br>
         * dbServer:        JDBC connect string. e.g. 'jdbc:oracle:thin:@203.92.21.109:1526:orcl'<br>
         * dbLogin:         Database login name.  e.g. 'Scott'<br>
         * dbPassword:      Database password.    e.g. 'Tiger'<br>
         * minConns:        Minimum number of connections to start with.<br>
         * maxConns:        Maximum number of connections in dynamic pool.<br>
         * logFileString:   Absolute path name for log file. e.g. 'c:\temp\mylog.log' <br>
         * maxConnTime:     Time in days between connection resets. (Reset does a basic cleanup)<br>
         */
        public ConnectionPool (String dbDriver, String dbServer, String dbLogin,
                String dbPassword, int minConns, int maxConns,
                    String logFileString, double maxConnTime) throws IOException
        {
            connPool = new Connection[maxConns];
            connStatus = new int[maxConns];
            connLockTime = new long[maxConns];
            connCreateDate = new long[maxConns];
            connID = new String[maxConns];
            currConnections = minConns;
            this.maxConns = maxConns;
            this.dbDriver = dbDriver;
            this.dbServer = dbServer;
            this.dbLogin = dbLogin;
            this.dbPassword = dbPassword;
            this.logFileString = logFileString;
            maxConnMSec = (int)(maxConnTime * 86400000.0);  //86400 sec/day
            if(maxConnMSec < 30000) {  // Recycle no less than 30 seconds.
                maxConnMSec = 30000;
            }

            try {
                log = new PrintWriter(new FileOutputStream(logFileString),true);

                // Can't open the requested file. Open the default file.
            }
            catch (IOException e1) {
                System.err.println("Warning: DbConnectionDefaultPool could not open \""
                    + logFileString + "\" to write log to. Make sure that your Java " +
                    "process has permission to write to the file and that the directory exists."
                );
                try {
                    log = new PrintWriter(new FileOutputStream("DCB_" +
                        System.currentTimeMillis() + ".log"), true
                    );
                }
                catch (IOException e2) {
                    throw new IOException("Can't open any log file");
                }
            }

            // Write the pid file (used to clean up dead/broken connection)
            SimpleDateFormat formatter
                = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz");
            java.util.Date nowc = new java.util.Date();
            pid = formatter.format(nowc);

            BufferedWriter pidout = new BufferedWriter(new
                                    FileWriter(logFileString + "pid"));
            pidout.write(pid);
            pidout.close();

            log.println("Starting ConnectionPool:");
            log.println("dbDriver = " + dbDriver);
            log.println("dbServer = " + dbServer);
            log.println("dbLogin = " + dbLogin);
            log.println("log file = " + logFileString);
            log.println("minconnections = " + minConns);
            log.println("maxconnections = " + maxConns);
            log.println("Total refresh interval = " + maxConnTime + " days");
            log.println("-----------------------------------------");

        
            // Initialize the pool of connections with the mininum connections:
            // Problems creating connections may be caused during reboot when the
            //    servlet is started before the database is ready.  Handle this
            //    by waiting and trying again.  The loop allows 5 minutes for
            //    db reboot.
            boolean connectionsSucceeded=false;
            int dbLoop=20;
        
            try {
                for(int i=1; i < dbLoop; i++) {
                    try {
                        for(int j=0; j < currConnections; j++) {
                            log.println("Create Conn "+j);
                            createConn(j);
                        }
                        connectionsSucceeded=true;
                        break;
                    }
                    catch (SQLException e){
                        log.println("--->Attempt (" + String.valueOf(i) +
                                " of " + String.valueOf(dbLoop) +
                                ") failed to create new connections set at startup: ");
                        log.println("    " + e);
                        log.println("    Will try again in 15 seconds...");
                        try { Thread.sleep(15000); }
                        catch(InterruptedException e1) {}
                    }
                }
                if(!connectionsSucceeded) { // All attempts at connecting to db exhausted
                    log.println("\r\nAll attempts at connecting to Database exhausted");
                    throw new IOException();
                }
            }
            catch (Exception e) {
                throw new IOException();
            }
        
            // Fire up the background housekeeping thread

            runner = new Thread(this);
            runner.start();

        } //End ConnectionPool()

//文件:DbConnectionDefaultPool.java的第二部分


        /**
         * Housekeeping thread.  Runs in the background with low CPU overhead.
         * Connections are checked for warnings and closure and are periodically
         * restarted.
         * This thread is a catchall for corrupted
         * connections and prevents the buildup of open cursors. (Open cursors
         * result when the application fails to close a Statement).
         * This method acts as fault tolerance for bad connection/statement programming.
         */
        public void run() {
            boolean forever = true;
            Statement stmt=null;
            String currCatalog=null;

            while(forever) {

                // Make sure the log file is the one this instance opened
                // If not, clean it up!
                try {
                    BufferedReader in = new BufferedReader(new
                        FileReader(logFileString + "pid"));
                    String curr_pid = in.readLine();
                    if(curr_pid.equals(pid)) {
                        //log.println("They match = " + curr_pid);
                    }
                    else {
                        //log.println("No match = " + curr_pid);
                        log.close();

                        // Close all connections silently - they are definitely dead.
                        for(int i=0; i < currConnections; i++) {
                            try {
                                connPool[i].close();
                            }
                            catch (SQLException e1) {} // ignore
                        }
                        // Returning from the run() method kills the thread
                        return;
                    }
                    in.close();
                }
                catch (IOException e1) {
                    log.println("Can't read the file for pid info: " +
                        logFileString + "pid");
                }

                // Get any Warnings on connections and print to event file
                for(int i=0; i < currConnections; i++) {
                    try {
                        currSQLWarning = connPool[i].getWarnings();
                        if(currSQLWarning != null) {
                            log.println("Warnings on connection " +
                                String.valueOf(i) + " " + currSQLWarning);
                            connPool[i].clearWarnings();
                        }
                    }
                    catch(SQLException e) {
                        log.println("Cannot access Warnings: " + e);
                    }
                }

                for(int i=0; i < currConnections; i++) { // Do for each connection
                    long age = System.currentTimeMillis() - connCreateDate[i];

                    synchronized(connStatus) {
                        if(connStatus[i] > 0) { // In use, catch it next time!
                            continue;
                        }
                        connStatus[i] = 2; // Take offline (2 indicates housekeeping lock)
                    }
        
                    try {  // Test the connection with createStatement call
                        if(age > maxConnMSec) {  // Force a reset at the max conn time
                            throw new SQLException();
                        }

                        stmt = connPool[i].createStatement();
                        connStatus[i] = 0;  // Connection is O.K.
                        //log.println("Connection confirmed for conn = " +
                        //             String.valueOf(i));

                        // Some DBs return an object even if DB is shut down
                        if(connPool[i].isClosed()) {
                            throw new SQLException();
                        }
                        // Connection has a problem, restart it
                    }
                    catch(SQLException e) {
                        try {
                            log.println(new Date().toString() +
                            " ***** Recycling connection " +
                            String.valueOf(i) + ":");

                            connPool[i].close();
                            createConn(i);
                        }
                        catch(SQLException e1) {
                            log.println("Failed: " + e1);
                            connStatus[i] = 0;  // Can't open, try again next time
                        }
                    }
                    finally {
                        try {
                            if(stmt != null) {
                                stmt.close();
                            }
                        }
                        catch(SQLException e1){};
                    }
                }

                try {
                    Thread.sleep(20000);
                }  // Wait 20 seconds for next cycle
                catch(InterruptedException e) {
                    // Returning from the run method sets the internal
                    // flag referenced by Thread.isAlive() to false.
                    // This is required because we don't use stop() to
                    // shutdown this thread.
                    return;
                }
            }
        } // End run

        /**
         * This method hands out the connections in round-robin order.
         * This prevents a faulty connection from locking
         * up an application entirely.  A browser 'refresh' will
         * get the next connection while the faulty
         * connection is cleaned up by the housekeeping thread.
         *
         * If the min number of threads are ever exhausted, new
         * threads are added up the the max thread count.
         * Finally, if all threads are in use, this method waits
         * 2 seconds and tries again, up to ten times.  After that, it
         * returns a null.
         */
        public Connection getConnection() {

            Connection conn=null;

            if(available){
                boolean gotOne = false;

                for(int outerloop=1; outerloop<=10; outerloop++) {

                    try  {
                        int loop=0;
                        int roundRobin = connLast + 1;
                        if(roundRobin >= currConnections) roundRobin=0;

                        do {
                            synchronized(connStatus) {
                                if((connStatus[roundRobin] < 1) &&
                                        (! connPool[roundRobin].isClosed()))
                                {
                                    conn = connPool[roundRobin];
                                    connStatus[roundRobin]=1;
                                    connLockTime[roundRobin] =
                                        System.currentTimeMillis();
                                    connLast = roundRobin;
                                    gotOne = true;
                                    break;
                                }
                                else {
                                    loop++;
                                    roundRobin++;
                                    if(roundRobin >= currConnections) roundRobin=0;
                                }
                            }
                        }
                        while((gotOne==false)&&(loop < currConnections));
                    }
                    catch (SQLException e1) {}

                    if(gotOne) {
                        break;
                    }
                    else {
                        synchronized(this) {  // Add new connections to the pool
                            if(currConnections < maxConns) {
                                try {
                                    createConn(currConnections);
                                    currConnections++;
                                }
                                catch(SQLException e) {
                                    log.println("Unable to create new connection: " + e);
                                }
                            }
                        }

                        try { Thread.sleep(2000); }
                        catch(InterruptedException e) {}
                        log.println("-----> Connections Exhausted!  Will wait and try " +
                            "again in loop " +
                            String.valueOf(outerloop));
                    }
                } // End of try 10 times loop

            }
            else {
                log.println("Unsuccessful getConnection() request during destroy()");
            } // End if(available)

            return conn;
        }

        /**
         * Returns the local JDBC ID for a connection.
         */
        public int idOfConnection(Connection conn) {
            int match;
            String tag;

            try {
                tag = conn.toString();
            }
            catch (NullPointerException e1) {
                tag = "none";
            }

            match=-1;

            for(int i=0; i< currConnections; i++) {
                if(connID[i].equals(tag)) {
                    match = i;
                    break;
                }
            }
            return match;
        }

        /**
         * Frees a connection.  Replaces connection back into the main pool for
         * reuse.
         */
        public String freeConnection(Connection conn) {
            String res="";

            int thisconn = idOfConnection(conn);
            if(thisconn >= 0) {
                connStatus[thisconn]=0;
                res = "freed " + conn.toString();
                //log.println("Freed connection " + String.valueOf(thisconn) +
                //            " normal exit: ");
            }
            else {
                log.println("----> Could not free connection!!!");
            }

            return res;
        }

//文件:DbConnectionDefaultPool.java的第三部分


        /**
         * Returns the age of a connection -- the time since it was handed out to
         * an application.
         */
        public long getAge(Connection conn) { // Returns the age of the connection in millisec.
            int thisconn = idOfConnection(conn);
            return System.currentTimeMillis() - connLockTime[thisconn];
        }

        private void createConn(int i) throws SQLException {
             Date now = new Date();
             try {
                Class.forName (dbDriver);
                Properties dbProp = new Properties();
                //log.println("Creating.....");
                dbProp.put("user", dbLogin);
                dbProp.put("password", dbPassword);
                dbProp.put("characterEncoding","gb2112");
                //dbProp.put("useUnicode", "true");
        
                connPool[i] = DriverManager.getConnection
                          (dbServer,dbProp);
                //log.println("Created Ok...");
                connStatus[i]=0;
                connID[i]=connPool[i].toString();
                connLockTime[i]=0;
                connCreateDate[i] =  now.getTime();
            }
            catch (ClassNotFoundException e2) {}
                
            log.println(now.toString() + "  Opening connection " + String.valueOf(i) +
                    " " + connPool[i].toString() + ":");
        }
    
        /**
         * Shuts down the housekeeping thread and closes all connections
         * in the pool. Call this method from the destroy() method of the servlet.
         */

        /**
         * Multi-phase shutdown.  having following sequence:
         * <OL>
         * <LI><code>getConnection()</code> will refuse to return connections.
         * <LI>The housekeeping thread is shut down.<br>
         *    Up to the time of <code>millis</code> milliseconds after shutdown of
         *    the housekeeping thread, <code>freeConnection()</code> can still be
         *    called to return used connections.
         * <LI>After <code>millis</code> milliseconds after the shutdown of the
         *    housekeeping thread, all connections in the pool are closed.
         * <LI>If any connections were in use while being closed then a
         *    <code>SQLException</code> is thrown.
         * <LI>The log is closed.
         * </OL><br>
         * Call this method from a servlet destroy() method.
         *
         * @param      millis   the time to wait in milliseconds.
         * @exception  SQLException if connections were in use after
         * <code>millis</code>.
         */
        public void destroy(int millis) throws SQLException {
    
            // Checking for invalid negative arguments is not necessary,
            // Thread.join() does this already in runner.join().

            // Stop issuing connections
            available=false;

            // Shut down the background housekeeping thread
            runner.interrupt();

            // Wait until the housekeeping thread has died.
            try { runner.join(millis); }
            catch(InterruptedException e){} // ignore
        
            // The housekeeping thread could still be running
            // (e.g. if millis is too small). This case is ignored.
            // At worst, this method will throw an exception with the
            // clear indication that the timeout was too short.

            long startTime=System.currentTimeMillis();

            // Wait for freeConnection() to return any connections
            // that are still used at this time.
            int useCount;
            while((useCount=getUseCount())>0 && System.currentTimeMillis() - startTime <=  millis) {
                try { Thread.sleep(500); }
                catch(InterruptedException e) {} // ignore
            }

            // Close all connections, whether safe or not
            for(int i=0; i < currConnections; i++) {
                try {
                    connPool[i].close();
                }
                catch (SQLException e1)
                {
                    log.println("Cannot close connections on Destroy");
                }
            }

            if(useCount > 0) {
                //bt-test successful
                String msg="Unsafe shutdown: Had to close "+useCount+
                    " active DB connections after "+millis+"ms";
                log.println(msg);
                // Close all open files
                log.close();
                // Throwing following Exception is essential because servlet authors
                // are likely to have their own error logging requirements.
                throw new SQLException(msg);
            }

            // Close all open files
            log.close();

        }//End destroy()


        /**
         * Less safe shutdown.  Uses default timeout value.
         * This method simply calls the <code>destroy()</code> method
         * with a <code>millis</code>
         * value of 10000 (10 seconds) and ignores <code>SQLException</code>
         * thrown by that method.
         * @see     #destroy(int)
         */
        public void destroy() {
            try {
                destroy(10000);
            }
            catch(SQLException e) {}
        }

        /**
         * Returns the number of connections in use.
         */
        // This method could be reduced to return a counter that is
        // maintained by all methods that update connStatus.
        // However, it is more efficient to do it this way because:
        // Updating the counter would put an additional burden on the most
        // frequently used methods; in comparison, this method is
        // rarely used (although essential).
        public int getUseCount() {
            int useCount=0;
            synchronized(connStatus) {
                for(int i=0; i < currConnections; i++) {
                    if(connStatus[i] > 0) { // In use
                        useCount++;
                    }
                }
            }
            return useCount;
        }//End getUseCount()

        /**
         * Returns the number of connections in the dynamic pool.
         */
        public int getSize() {
            return currConnections;
        }//End getSize()

    }

    /**
     * An implementation of the Connection interface that wraps an underlying
     * Connection object. It releases the connection back to a connection pool
     * when Connection.close() is called.
     */
    public class ConnectionWrapper  implements Connection {

        private Connection connection;
        private ConnectionPool connectionPool;

        public ConnectionWrapper(Connection connection, ConnectionPool connectionPool) {
            this.connection = connection;
            this.connectionPool = connectionPool;
        }

        /**
         * Instead of closing the underlying connection, we simply release
         * it back into the pool.
         */
        public void close() throws SQLException {
            connectionPool.freeConnection(this.connection);
            //Release object references. Any further method calls on the
            //connection will fail.
            connection = null;
            connectionPool = null;
        }

        public Statement createStatement() throws SQLException {
            return connection.createStatement();
        }

        public PreparedStatement prepareStatement(String sql) throws SQLException {
            return connection.prepareStatement(sql);
        }

        public CallableStatement prepareCall(String sql) throws SQLException {
            return connection.prepareCall(sql);
        }

        public String nativeSQL(String sql) throws SQLException {
            return connection.nativeSQL(sql);
        }

        public void setAutoCommit(boolean autoCommit) throws SQLException {
            connection.setAutoCommit(autoCommit);
        }

        public boolean getAutoCommit() throws SQLException {
            return connection.getAutoCommit();
        }

        public void commit() throws SQLException {
            connection.commit();
        }

        public void rollback() throws SQLException {
            connection.rollback();
        }

        public boolean isClosed() throws SQLException {
            return connection.isClosed();
        }

        public DatabaseMetaData getMetaData() throws SQLException {
            return connection.getMetaData();
        }

        public void setReadOnly(boolean readOnly) throws SQLException {
            connection.setReadOnly(readOnly);
        }

        public boolean isReadOnly() throws SQLException {
            return connection.isReadOnly();
        }

        public void setCatalog(String catalog) throws SQLException {
            connection.setCatalog(catalog);
        }

        public String getCatalog() throws SQLException {
            return connection.getCatalog();
        }

        public void setTransactionIsolation(int level) throws SQLException {
            connection.setTransactionIsolation(level);
        }

        public int getTransactionIsolation() throws SQLException {
            return connection.getTransactionIsolation();
        }

        public SQLWarning getWarnings() throws SQLException {
            return connection.getWarnings();
        }

        public void clearWarnings() throws SQLException {
            connection.clearWarnings();
        }

        public Statement createStatement(int resultSetType, int resultSetConcurrency)
                throws SQLException
        {
            return connection.createStatement(resultSetType, resultSetConcurrency);
        }

        public PreparedStatement prepareStatement(String sql, int resultSetType,
                int resultSetConcurrency) throws SQLException
        {
            return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
        }

        public CallableStatement prepareCall(String sql, int resultSetType,
                int resultSetConcurrency) throws SQLException
        {
            return prepareCall(sql, resultSetType, resultSetConcurrency);
        }

        public Map getTypeMap() throws SQLException {
            return connection.getTypeMap();
        }

        public void setTypeMap(Map map) throws SQLException {
            connection.setTypeMap(map);
        }

    }
} //文件:DbConnectionManager.java

package com.qingtuo.db.pool;

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

/**
* Central manager of database connections.
*/
public class DbConnectionManager {

    private static DbConnectionProvider connectionProvider;
    private static Object providerLock = new Object();

    /**
     * Returns a database connection from the currently active connection
     * provider.
     */
    public static Connection getConnection() {
        if (connectionProvider == null) {
            synchronized (providerLock) {
                if (connectionProvider == null) {
                    //Create the connection provider -- for now, this is hardcoded. For
                    //the next beta, I'll change this to load up the provider dynamically.
                    connectionProvider = new DbConnectionDefaultPool();
                    connectionProvider.start();
                }
            }
        }
        Connection con = connectionProvider.getConnection();
        if (con == null) {
            System.err.println("WARNING: DbConnectionManager.getConnection() failed to obtain a connection.");
        }
        return con;
    }

    /**
     * Returns the current connection provider. The only case in which this
     * method should be called is if more information about the current
     * connection provider is needed. Database connections should always be
     * obtained by calling the getConnection method of this class.
     */
    public static DbConnectionProvider getDbConnectionProvider() {
        return connectionProvider;
    }

    /**
     * Sets the connection provider. The old provider (if it exists) is shut
     * down before the new one is started. A connection provider <b>should
     * not</b> be started before being passed to the connection manager.
     */
    public static void setDbConnectionProvider(DbConnectionProvider provider) {
        synchronized (providerLock) {
            if (connectionProvider != null) {
                connectionProvider.destroy();
                connectionProvider = null;
            }
            connectionProvider = provider;
            provider.start();
        }
    }


}