package com.github.walker.easydb.connection; import com.github.walker.easydb.assistant.EasyConfig; import com.github.walker.easydb.exception.DataAccessException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Vector; /** * <p> * Self-realized connection pool. * </p> * * @author HuQingmiao */ class EasyDBConnPool extends ConnectionPool { // the max intercurrent connection number of self-realize connection pool. private static String maxConnCnts = EasyConfig.getProperty("maxConnCount"); // the maximum intercurrent count of private static int maxConnCount = Integer.parseInt(maxConnCnts); // connection pool private static int usedConnCount; // the count of used connection private static Vector<Connection> freeConnQueue = new Vector<Connection>(); // the // free // connection // the rate of idle connections to activity connections private static float maxIdleRate = (float) 1 / 3; // JDBC driver String, such as: "com.mysql.jdbc.Driver" private String driverStr = EasyConfig.getProperty("driverStr"); // datasource, such as: "jdbc:mysql://127.0.0.1:3306/test" private String dataSource = EasyConfig.getProperty("dataSource"); private String username = EasyConfig.getProperty("username"); private String password = EasyConfig.getProperty("password"); private String dbType = EasyConfig.getProperty("DBType"); protected EasyDBConnPool() { log.info("Self-realized connection pool is adopted. "); } /** * Retrieve the database connection * * @return database connection */ @SuppressWarnings("resource") public synchronized Connection getConnection() throws DataAccessException { Connection con = null; // if exists free connection if (freeConnQueue.size() > 0) { // Retrieve the first connection of the free queue con = (Connection) freeConnQueue.firstElement(); freeConnQueue.removeElementAt(0); try { // If the connection is not avaliable, recall this method // recursively if (con == null || con.isClosed()) { con = getConnection(); } else { // if the rate of idel to activity is greater than 1/3 if (freeConnQueue.size() / (float) usedConnCount > maxIdleRate) { trimQueue((int) (usedConnCount * maxIdleRate)); } } } catch (SQLException e) { con = getConnection(); } } else { try { if (usedConnCount < maxConnCount) { con = newConnection(); } else { log.info("The used connection count is:" + usedConnCount); log.info("The size of free queue is :" + freeConnQueue.size()); log.warn("the setted maximum intercurrent count of connection is not big enough, or the intercurrent users are too more. "); // spends three seconds to wait for other free connection Thread.sleep(2000); getConnection(); } } catch (SQLException e) { log.error(e.getErrorCode(), e); throw new DataAccessException(this.getDBType(), e.getErrorCode(), e.getMessage()); } catch (ClassNotFoundException e) { log.error("", e); } catch (InterruptedException e) { log.error("", e); } } usedConnCount++; // notify the threads which are waiting for enter this method this.notifyAll(); log.debug("The used connection count is:" + usedConnCount); log.debug("The size of free queue is :" + freeConnQueue.size()); return con; } /** * Releases the connecion and adds it into the tail of free connection queue * in order to recycle and reuse it. */ public synchronized void freeConnection(Connection conn) { // adds the connection into the tail of free connection queue freeConnQueue.addElement(conn); usedConnCount--; // notify the threads which are waiting for enter this method this.notifyAll(); } /** * Creates a new connection. */ private java.sql.Connection newConnection() throws SQLException, ClassNotFoundException { java.sql.Connection conn = null; try { Class.forName(driverStr); log.info("Trying to connect to " + dataSource); conn = DriverManager.getConnection(dataSource, username, password); log.info("Creating new Connection... OK! "); } catch (SQLException e) { // log.error("Creating new Connection... FAILED!",e); throw e; } catch (ClassNotFoundException e) { // log.error("",e); throw e; } return conn; } /** * Releases all the connecions in the free connection queue. */ private synchronized void trimQueue(int resize) throws SQLException { int size = freeConnQueue.size(); while (size > resize) { Connection c = freeConnQueue.get(size - 1); if (c != null && !c.isClosed()) { c.close(); } freeConnQueue.remove(size - 1); size--; } } /** * Releases all the connecions in the free connection queue. */ private void freeAll() throws SQLException { for (int i = 0; i < freeConnQueue.size(); i++) { Connection c = freeConnQueue.get(i); if (c != null && !c.isClosed()) { c.close(); } } freeConnQueue.clear(); usedConnCount = 0; } protected void finalize() { try { this.freeAll(); } catch (SQLException e) { log.error("", e); } } /** * 获取数据库类型 * * @return */ public String getDBType() { return this.dbType; } }