A JAVA database connection pool implementation source code

//
// A very good JAVA database connection pool.
//    from:http://www.jxer.com/home/?uid-195-action-viewspace-itemid-332
// Although it is very convenient to use APACHE COMMONS DBCP to establish a database connection pool,
// But like this article, the internal principles of the database connection pool are written so thoroughly and the attention is so complete.
// It's really rare, so that developers can have a deeper understanding of the database connection pool, it's really impressive
// Thanks to the author of this article.
//
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Vector;

public class ConnectionPool {

    private String jdbcDriver = ""; // database driver
    private String dbUrl = ""; // data URL
    private String dbUsername = ""; // database username
    private String dbPassword = ""; // database user password
    private String testTable = ""; // The name of the test table to test whether the connection is available, there is no test table by default
    private int initialConnections = 10; // initial size of the connection pool
    private int incrementalConnections = 5; // Automatically increase the size of the connection pool
    private int maxConnections = 50; // maximum size of connection pool
    private Vector connections = null; // The vector that stores the database connection in the connection pool, initially null
// The object stored in it is of type PooledConnection

   
    public ConnectionPool(String jdbcDriver, String dbUrl, String dbUsername,
                          String dbPassword) {

        this.jdbcDriver = jdbcDriver;
        this.dbUrl = dbUrl;
        this.dbUsername = dbUsername;
        this.dbPassword = dbPassword;
    }

   
    public int getInitialConnections() {
        return this.initialConnections;
    }

   
    public void setInitialConnections(int initialConnections) {
        this.initialConnections = initialConnections;
    }

   
    public int getIncrementalConnections() {
        return this.incrementalConnections;
    }

   
    public void setIncrementalConnections(int incrementalConnections) {
        this.incrementalConnections = incrementalConnections;
    }

   
    public int getMaxConnections() {
        return this.maxConnections;
    }

   
    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

   
    public String getTestTable() {
        return this.testTable;
    }

   
    public void setTestTable(String testTable) {
        this.testTable = testTable;
    }

   
    public synchronized void createPool() throws Exception {
        // Make sure the connection pool is not created
        // If the connection pool has been created, the vector connections that hold the connection will not be empty
        if (connections != null) {
            return; // if already created, return
        }
        // Instantiate the instance of the driver class specified in the JDBC Driver
        Driver driver = (Driver) (Class.forName(this.jdbcDriver).newInstance());
        DriverManager.registerDriver(driver); // Register the JDBC driver
        // Create a vector holding connections, initially with 0 elements
        connections = new Vector();
        // Create a connection based on the value set in initialConnections.
        createConnections(this.initialConnections);
        System.out.println("The database connection pool was created successfully! ");
    }

   
    private void createConnections(int numConnections) throws SQLException {
        // Loop to create the specified number of database connections
        for (int x = 0; x < numConnections; x++) {
            // Has the maximum number of database connections in the connection pool been reached? The maximum value is determined by the class member maxConnections
            // Point out that if maxConnections is 0 or negative, there is no limit to the number of connections.
            // If the number of connections has reached the maximum, exit.
            if (this.maxConnections > 0 &&
                this.connections.size() >= this.maxConnections) {
                break;
            }
            //add a new PooledConnection object to connections vector
            // Add a connection to the connection pool (in the vector connections)
            try {
                connections.addElement(new PooledConnection(newConnection()));
            } catch (SQLException e) {
                System.out.println("Failed to create database connection! " + e.getMessage());
                throw new SQLException();
            }
            System.out.println("Database connection created...");
        }
    }

   
    private Connection newConnection() throws SQLException {
        // create a database connection
        Connection conn = DriverManager.getConnection(dbUrl, dbUsername,
                dbPassword);
        // If this is the first time to create a database connection, check the database to get what the database promises to support
        // maximum number of client connections
        //connections.size()==0 means that no connection has been created
        if (connections.size() == 0) {
            DatabaseMetaData metaData = conn.getMetaData();
            int driverMaxConnections = metaData.getMaxConnections();
            // If the driverMaxConnections returned by the database is 0, it means that the database has no maximum
            // Connection limit, or the maximum connection limit of the database is not known
            //driverMaxConnections is an integer returned, indicating the number of client connections allowed by this database
            // If the maximum number of connections set in the connection pool is greater than the number of connections allowed by the database, set the maximum number of connections in the connection pool
            // The number of connections is the maximum number allowed by the database
            if (driverMaxConnections > 0 &&
                this.maxConnections > driverMaxConnections) {
                this.maxConnections = driverMaxConnections;
            }
        }
        return conn; // return the new database connection created
    }

   

    public synchronized Connection getConnection() throws SQLException {
        // Make sure the connection pool has been created
        if (connections == null) {
            return null; // If the connection pool has not been created, return null
        }
        Connection conn = getFreeConnection(); // get a free database connection
        // If there are currently no available connections, all connections are in use
        while (conn == null) {
            // try again later
            wait(250);
            conn = getFreeConnection(); // retry until a free connection is obtained, if
            //getFreeConnection() returns null
            // Indicates that no available connections are available after a batch of connections is created
        }
        return conn; // return the available connection obtained
    }

   
    private Connection getFreeConnection() throws SQLException {
        // Get an available database connection from the connection pool
        Connection conn = findFreeConnection();
        if (conn == null) {
            // If there is no connection available in the current connection pool
            // create some connections
            createConnections(incrementalConnections);
            // Re-check if there is an available connection from the pool
            conn = findFreeConnection();
            if (conn == null) {
                // If no available connection is available after the connection is created, return null
                return null;
            }
        }
        return conn;
    }

   
    private Connection findFreeConnection() throws SQLException {
        Connection conn = null;
        PooledConnection pConn = null;
        // Get all objects in the connection pool vector
        Enumeration enumerate = connections.elements();
        // loop through all objects to see if there is any connection available
        while (enumerate.hasMoreElements()) {
            pConn = (PooledConnection) enumerate.nextElement();
            if (!pConn.isBusy()) {
                // If this object is not busy, get its database connection and make it busy
                conn = pConn.getConnection();
                pConn.setBusy(true);
                // Test if this connection is available
                if (!testConnection(conn)) {
                    // If this connection is no longer available, create a new connection,
                    // and replace this unavailable connection object, if the creation fails, return null
                    try {
                        conn = newConnection();
                    } catch (SQLException e) {
                        System.out.println("Failed to create database connection! " + e.getMessage());
                        return null;
                    }
                    pConn.setConnection(conn);
                }
                break; // found an available connection, exit
            }
        }
        return conn; // return the found available connection
    }

   
    private boolean testConnection(Connection conn) {
        try {
            // Determine if the test table exists
            if (testTable.equals("")) {
                // If the test table is empty, try to use the setAutoCommit() method of this connection
                // To determine whether the connection is available (this method is only available in some databases, if not available,
                // Throw an exception). Note: The method using the test table is more reliable
                conn.setAutoCommit(true);
            } else { // Use the test table to test when there is a test table
                //check if this connection is valid
                Statement stmt = conn.createStatement();
                stmt.execute("select count(*) from " + testTable);
            }
        } catch (SQLException e) {
            // The above throws an exception, this connection is not available, close it, and return false;
            closeConnection(conn);
            return false;
        }
        // connection is available, return true
        return true;
    }

   
    public void returnConnection(Connection conn) {
        // Make sure the connection pool exists, if the connection is not created (doesn't exist), return directly
        if (connections == null) {
            System.out.println("The connection pool does not exist, cannot return this connection to the connection pool!");
            return;
        }
        PooledConnection pConn = null;
        Enumeration enumerate = connections.elements();
        // Traverse all connections in the connection pool to find the connection object to return
        while (enumerate.hasMoreElements()) {
            pConn = (PooledConnection) enumerate.nextElement();
            // First find the connection object to be returned in the connection pool
            if (conn == pConn.getConnection()) {
                // found, set this connection to idle state
                pConn.setBusy(false);
                break;
            }
        }
    }

   

    public synchronized void refreshConnections() throws SQLException {
        // Make sure that the connection pool has been created
        if (connections == null) {
            System.out.println("The connection pool does not exist and cannot be refreshed!");
            return;
        }
        PooledConnection pConn = null;
        Enumeration enumerate = connections.elements();
        while (enumerate.hasMoreElements()) {
            // get a connection object
            pConn = (PooledConnection) enumerate.nextElement();
            // If the object is busy, wait 5 seconds, and refresh directly after 5 seconds
            if (pConn.isBusy()) {
                wait(5000); // wait 5 seconds
            }
            // Close this connection and replace it with a new one.
            closeConnection(pConn.getConnection());
            pConn.setConnection(newConnection());
            pConn.setBusy(false);
        }
    }

   
    public synchronized void closeConnectionPool() throws SQLException {
        // Make sure the connection pool exists, if not, return
        if (connections == null) {
            System.out.println("The connection pool does not exist and cannot be closed!");
            return;
        }
        PooledConnection pConn = null;
        Enumeration enumerate = connections.elements();
        while (enumerate.hasMoreElements()) {
            pConn = (PooledConnection) enumerate.nextElement();
            // if busy, wait 5 seconds
            if (pConn.isBusy()) {
                wait(5000); // wait 5 seconds
            }
            //Close it directly after 5 seconds
            closeConnection(pConn.getConnection());
            // remove it from the connection pool vector
            connections.removeElement(pConn);
        }
        // set the connection pool to be empty
        connections = null;
    }

   
    private void closeConnection(Connection conn) {
        try {
            conn.close();
        } catch (SQLException e) {
            System.out.println("Error closing database connection: " + e.getMessage());
        }
    }

   
    private void wait(int mSeconds) {
        try {
            Thread.sleep(mSeconds);
        } catch (InterruptedException e) {
        }
    }

   

    class PooledConnection {
        Connection connection = null; // database connection
        boolean busy = false; // The flag of whether this connection is in use, the default is not in use
        // Constructor, according to a Connection to construct a PooledConnection object
        public PooledConnection(Connection connection) {
            this.connection = connection;
        }

        // return the connection in this object
        public Connection getConnection() {
            return connection;
        }

        // set this object's, connection
        public void setConnection(Connection connection) {
            this.connection = connection;
        }

        // Get whether the object connection is busy
        public boolean isBusy() {
            return busy;
        }

        // set the connection to the object is busy
        public void setBusy(boolean busy) {
            this.busy = busy;
        }
    }


    public static void main(String[] args) {
       
        ConnectionPool connPool
                = new ConnectionPool("oracle.jdbc.driver.OracleDriver",
                                     "jdbc:oracle:thin:@*.*.*.*"
                                     , "name", "password");

        try {
            connPool.createPool();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        try {
            Connection conn = connPool.getConnection();
        } catch (SQLException ex1) {
            ex1.printStackTrace();
        }

    }

}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326520947&siteId=291194637