import com.tanghd.main.config.ConfigPO; import com.tanghd.utils.NumberUtils; import java.sql.Connection; import java.sql.DriverManager; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Timer; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Semaphore; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * 数据库连接池 */ public class ConnectionPool { /** * 单实例 */ private static ConnectionPool instance = new ConnectionPool(); public static Log log = LogFactory.getLog(ConnectionPool.class); /** * 用于保存数据库连接 */ private static ConcurrentLinkedQueue<Connection> pool = new ConcurrentLinkedQueue<Connection>(); /** * 保存当前被使用中是连接 */ private static BlockingQueue<Connection> using = null; /** * 信号量,控制最多多少个请求同时能获取到连接 */ private static Semaphore position; /** * 最大连接数 */ private static int MAX = 30; /** * 初始化连接数 */ private static int INIT = 15; /** * 数据库连接URL */ private static String url; /** * 数据库连接用户名 */ private static String user; /** * 数据库连接密码 */ private static String password; /** * 数据库连接驱动 */ private static String driver; private static long connectionColloctPeriod = 0; private static Timer cleanTask; public static ConnectionPool getInstance() { return instance; } /** * 初始化,应用启动时调用 * * @throws Exception */ public synchronized static void init() throws Exception { initParameters(); initPool(); position = new Semaphore(MAX); } /** * 从连接池中获取连接,如果为空,则新建连接 由于有信号量控制,所以不检查当前生成的连接是否已达到最大限制 * * @return * @throws Exception */ public Connection getConnection() throws Exception { position.acquire(); Connection conn = pool.poll(); if (null == conn) { log.debug("create a new connnection "); conn = createNewConnection(); } else { log.debug("use an old connnection "); } ConnectionWapper tmpConn = (ConnectionWapper) conn; tmpConn.setIsInPool(false); using.add(conn); return conn; } /** * 关闭连接,并返回连接池中 * * @param conn */ public void closeConnection(ConnectionWapper conn) { if (null != conn) { try { conn.commit(); if (!conn.isClosed()) { pool.add(conn); ConnectionWapper tmpConn = (ConnectionWapper) conn; tmpConn.setIsInPool(true); tmpConn.setLastUseTime(System.currentTimeMillis()); using.remove(conn); } } catch (Exception e) { log.error(e); } log.debug("release a connection into pool."); position.release(); } } /** * 初始化连接池,预先生成 * * @throws Exception */ private static void initPool() throws Exception { List<Connection> tmpArray = new ArrayList<Connection>(INIT); for (int i = 0; i < INIT; i++) { tmpArray.add(instance.createNewConnection()); } pool.addAll(tmpArray); tmpArray = null; using = new ArrayBlockingQueue<Connection>(MAX+INIT); if (connectionColloctPeriod > 0) { cleanTask = new Timer(); cleanTask.schedule(new ConnectionCollector(ConnectionPool.getInstance(), connectionColloctPeriod), connectionColloctPeriod, connectionColloctPeriod); } } /** * 加载参数 */ private static void initParameters() { url = ConfigPO.getConfig("db_url"); user = ConfigPO.getConfig("db_user"); password = ConfigPO.getConfig("db_pwd"); driver = ConfigPO.getConfig("db_driver"); MAX = NumberUtils.parseInteger(ConfigPO.getConfig("db_max_connections"), 30); INIT = NumberUtils.parseInteger(ConfigPO.getConfig("db_init_connections"), 15); connectionColloctPeriod = NumberUtils.parseLong(ConfigPO.getConfig("db_clean_connections_period"), 0); } /** * 新建连接 * * @return * @throws Exception */ private Connection createNewConnection() throws Exception { ConnectionWapper conn = null; try { Class.forName(driver).newInstance(); Connection con = DriverManager.getConnection(url, user, password); conn = new ConnectionWapper(con); } catch (Exception ex) { log.error(ex); throw ex; } return conn; } public void clearOldConnections(long period) { long current = System.currentTimeMillis(); synchronized (pool) { Iterator<Connection> iter = pool.iterator(); while (iter.hasNext()) { ConnectionWapper conn = (ConnectionWapper) iter.next(); if (conn.isIsInPool()) { if (conn.getLastUseTime() - current > period) { try { conn.getConn().close(); } catch (Exception e) { log.error(e); } iter.remove(); log.info("remove an old connection"); } } } } } }
import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Savepoint; import java.sql.Statement; import java.util.Map; /** * 数据库连接 */ public class ConnectionWapper implements Connection { /** * 数据库连接 */ private Connection conn; /** * 是否在连接池里,如果是true,调用该连接的时候,会抛出异常 */ private boolean isInPool; /** * 最后一次调用放入连接池的时间 */ private long lastUseTime; public Connection getConn() { return conn; } public boolean isIsInPool() { return isInPool; } public void setIsInPool(boolean isInPool) { this.isInPool = isInPool; } public long getLastUseTime() { return lastUseTime; } public void setLastUseTime(long lastUseTime) { this.lastUseTime = lastUseTime; } private void checkPooling() throws SQLException { if (isInPool) { throw new SQLException("已关闭的连接"); } } public void close() throws SQLException { ConnectionPool.getInstance().closeConnection(this); } public ConnectionWapper(Connection conn) { this.conn = conn; } public Statement createStatement() throws SQLException { checkPooling(); return this.conn.createStatement(); } public PreparedStatement prepareStatement(String sql) throws SQLException { checkPooling(); return this.conn.prepareStatement(sql); } public CallableStatement prepareCall(String sql) throws SQLException { checkPooling(); return this.conn.prepareCall(sql); } public String nativeSQL(String sql) throws SQLException { checkPooling(); return this.conn.nativeSQL(sql); } public void setAutoCommit(boolean autoCommit) throws SQLException { checkPooling(); this.conn.setAutoCommit(autoCommit); } public boolean getAutoCommit() throws SQLException { checkPooling(); return this.conn.getAutoCommit(); } public void commit() throws SQLException { checkPooling(); this.conn.commit(); } public void rollback() throws SQLException { checkPooling(); this.conn.rollback(); } public boolean isClosed() throws SQLException { checkPooling(); return this.conn.isClosed(); } public DatabaseMetaData getMetaData() throws SQLException { checkPooling(); return this.conn.getMetaData(); } public void setReadOnly(boolean readOnly) throws SQLException { checkPooling(); this.conn.setReadOnly(readOnly); } public boolean isReadOnly() throws SQLException { checkPooling(); return this.conn.isReadOnly(); } public void setCatalog(String catalog) throws SQLException { checkPooling(); this.conn.setCatalog(catalog); } public String getCatalog() throws SQLException { checkPooling(); return this.conn.getCatalog(); } public void setTransactionIsolation(int level) throws SQLException { checkPooling(); this.conn.setTransactionIsolation(level); } public int getTransactionIsolation() throws SQLException { checkPooling(); return this.conn.getTransactionIsolation(); } public SQLWarning getWarnings() throws SQLException { checkPooling(); return this.conn.getWarnings(); } public void clearWarnings() throws SQLException { checkPooling(); this.conn.clearWarnings(); } public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { checkPooling(); return this.conn.createStatement(resultSetType, resultSetConcurrency); } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkPooling(); return this.conn.prepareStatement(sql, resultSetType, resultSetConcurrency); } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkPooling(); return this.conn.prepareCall(sql, resultSetType, resultSetConcurrency); } public Map<String, Class<?>> getTypeMap() throws SQLException { checkPooling(); return this.conn.getTypeMap(); } public void setTypeMap(Map<String, Class<?>> map) throws SQLException { checkPooling(); this.conn.setTypeMap(map); } public void setHoldability(int holdability) throws SQLException { checkPooling(); this.conn.setHoldability(holdability); } public int getHoldability() throws SQLException { checkPooling(); return this.conn.getHoldability(); } public Savepoint setSavepoint() throws SQLException { checkPooling(); return this.conn.setSavepoint(); } public Savepoint setSavepoint(String name) throws SQLException { checkPooling(); return this.conn.setSavepoint(name); } public void rollback(Savepoint savepoint) throws SQLException { checkPooling(); this.conn.rollback(savepoint); } public void releaseSavepoint(Savepoint savepoint) throws SQLException { checkPooling(); this.conn.releaseSavepoint(savepoint); } public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkPooling(); return this.conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkPooling(); return this.conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkPooling(); return this.conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { checkPooling(); return this.conn.prepareStatement(sql, autoGeneratedKeys); } public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { checkPooling(); return this.conn.prepareStatement(sql, columnIndexes); } public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { checkPooling(); return this.conn.prepareStatement(sql, columnNames); } }