写了个 Java数据库连接池,具备基本的功能点:
1、对池中活动连接的重用。
2、池满时的适时等待。
3、对空闲连接的适时关闭。
抛砖引玉,走过路过,不吝赐教。
?
DBConnection.java如下:
?
package db; import java.sql.Connection; import java.util.concurrent.atomic.AtomicBoolean; /** * 封装的连接 * @author Linkwork, 276247076@qq.com * @since 2014年11月01日 */ public class DBConnection { /** * 原生的连接 */ private Connection connection = null; /** * 是否空闲 */ private AtomicBoolean idle = null; /** * 最近一次的空闲开始时间 */ private volatile long idleStart = 0L; /** * 标识 */ private int index = -1; /** * 构造函数 * @param index 标识 * @param connection 连接 * @param idle 是否空闲 */ public DBConnection(int index, Connection connection, boolean idle) { this.index = index; this.connection = connection; this.idle = new AtomicBoolean(idle); } /** * 释放 */ public void release() { if (this.idle.compareAndSet(false, true)) { this.idleStart = System.currentTimeMillis(); } } public Connection getConnection() { return connection; } public AtomicBoolean getIdle() { return idle; } public void setConnection(Connection connection) { this.connection = connection; } public int getIndex() { return index; } public long getIdleStart() { return idleStart; } public void setIdleStart(long idleStart) { this.idleStart = idleStart; } }
?DBConnectionPool.java如下:
?
?
package db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Vector; /** * 数据库连接池 * @author Linkwork, 276247076@qq.com * @since 2014年11月01日 */ public class DBConnectionPool extends Thread { /** * 容量 */ private volatile int capacity = 1; /** * 驱动 */ private String driver = null; /** * 地址 */ private String url = null; /** * 用户名 */ private String user = null; /** * 密码 */ private String password = null; /** * 等待的轮询间隔 */ private volatile long waitInterval = 50L; /** * 等待的超时时间,默认 2分钟 */ private volatile long waitTimeout = 120000L; /** * 空闲的超时时间,默认 5分钟 */ private volatile long idleTimeout = 300000L; /** * 连接集 */ private Vector<DBConnection> dbconnectionLst = null; /** * 是否正在进行关闭 */ private volatile boolean closing = false; /** * 构造函数 * @param capacity 容量 * @param driver 驱动 * @param url 地址 * @param user 用户名 * @param password 密码 */ public DBConnectionPool( int capacity, String driver, String url, String user, String password) { this.capacity = capacity; this.driver = driver; this.url = url; this.user = user; this.password = password; this.dbconnectionLst = new Vector<DBConnection>(); } /** * 获取 DB连接 * @return */ public DBConnection getDBConnectionQuietly() { try { return this.getDBConnection(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 获取 DB连接 * @return * @throws Exception */ public DBConnection getDBConnection() throws Exception { long start = System.currentTimeMillis(); // 当不是正在进行关闭 while (! this.closing) { // 遍历连接集,获取空闲、可用的连接 for (DBConnection dbconnection: this.dbconnectionLst) { if (dbconnection.getIdle().compareAndSet(true, false)) { // 若连接未关闭 if (! this.isNullOrClose(dbconnection)) { return dbconnection; } else { if (! this.closing) { dbconnection.getIdle().set(true); } } } } // 若连接的总数未超出容量,则新建连接 if ((this.dbconnectionLst.size() < this.capacity) && (! this.closing)) { synchronized (this.dbconnectionLst) { DBConnection dbconnection = this.createDBConnection(this.dbconnectionLst.size() + 1); this.dbconnectionLst.add(dbconnection); return dbconnection; } } // 遍历连接集,重用空闲、不可用的连接 for (DBConnection dbconnection: this.dbconnectionLst) { if (dbconnection.getIdle().compareAndSet(true, false)) { // 若连接已关闭 if ((null == dbconnection.getConnection()) || dbconnection.getConnection().isClosed()) { Connection connection = this.createConnection(); dbconnection.setConnection(connection); return dbconnection; } else if (! this.closing) { dbconnection.getIdle().set(true); } } } // 延迟轮询 Thread.sleep(this.waitInterval); long end = System.currentTimeMillis(); // 若等待超时 if (end - start > this.waitTimeout) { throw new Exception("ERROR_WAIT_TIMEOUT"); } start = end; } // while (! this.closing) { return null; } /** * 关闭连接池中的所有连接 * @throws Exception */ public void close() { this.closing = true; // 是否已经关闭 boolean closed = false; // 当未关闭完成 while (! closed) { closed = true; try { Thread.sleep(this.waitInterval); } catch (Exception e) { e.printStackTrace(); return; } // 遍历连接集,关闭所有空闲连接 for (DBConnection dbconnection: this.dbconnectionLst) { // 若连接空闲,则关闭该连接,并标记未关闭完成 if (dbconnection.getIdle().compareAndSet(true, false)) { closed = false; try { if (! this.isNullOrClose(dbconnection)) { dbconnection.getConnection().close(); } } catch (Exception e) { e.printStackTrace(); } } } } // while (true) { System.out.println("has closed all!"); } @Override public void run() { // 当不是正在进行关闭 while (! this.closing) { try { // 延迟轮询 Thread.sleep(this.waitInterval); // 遍历连接集,关闭空闲超时的连接 for (DBConnection dbconnection: this.dbconnectionLst) { // 若连接空闲,且空闲超时 if (dbconnection.getIdle().get() && this.idleTimeout(dbconnection) && dbconnection.getIdle().compareAndSet(true, false)) { // 若连接空闲超时 if (this.idleTimeout(dbconnection)) { dbconnection.setIdleStart(0L); dbconnection.getConnection().close(); System.out.println("【dbconnection-" + dbconnection.getIndex() + "】idle timeout."); } if (! this.closing) { dbconnection.getIdle().set(true); } } } } catch (Exception e) { e.printStackTrace(); } } } public int getCapacity() { return capacity; } public void setCapacity(int capacity) { this.capacity = capacity; } public long getWaitTimeout() { return waitTimeout; } public void setWaitTimeout(long waitTimeout) { this.waitTimeout = waitTimeout; } public long getIdleTimeout() { return idleTimeout; } public void setIdleTimeout(long idleTimeout) { this.idleTimeout = idleTimeout; } public long getWaitInterval() { return waitInterval; } public void setWaitInterval(long waitInterval) { this.waitInterval = waitInterval; } /** * 创建 DB连接 * @param index * @return * @throws Exception */ private DBConnection createDBConnection(int index) throws Exception { return new DBConnection(index, this.createConnection(), false); } /** * 创建连接 * @return * @throws Exception */ private Connection createConnection() throws Exception { Class.forName(this.driver); return DriverManager.getConnection(this.url, this.user, this.password); } /** * DB连接是否空闲超时 * @param dbconnection * @return */ private boolean idleTimeout(DBConnection dbconnection) { return ((dbconnection.getIdleStart() > 0) && (System.currentTimeMillis() - dbconnection.getIdleStart() > this.idleTimeout)); } /** * DB连接是否为空、或已关闭 * @param dbconnection * @return * @throws SQLException */ private boolean isNullOrClose(DBConnection dbconnection) throws SQLException { return ((null == dbconnection.getConnection()) || dbconnection.getConnection().isClosed()); } }
?DBConnectionPoolTest.java如下
?
?
package db; import java.sql.PreparedStatement; import java.text.SimpleDateFormat; import java.util.Date; /** * 测试:数据库连接池 * @author Linkwork, 276247076@qq.com * @since 2014年11月0日 */ public class DBConnectionPoolTest { public static void main(String[] args) { DBConnectionPool pool = new DBConnectionPool(3, "com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/db", "lw2013qq", "omg2056db4qq"); pool.setWaitTimeout(10000L); pool.setIdleTimeout(40L); pool.start(); testPool(pool); pool.close(); } /** * 测试连接池 * @param pool */ public static void testPool(DBConnectionPool pool) { DBConnection dbconnection = pool.getDBConnectionQuietly(); if (null != dbconnection) { try { // 创建表 dbconnection.getConnection().prepareStatement("create table if not exists test_pool (tp_value int);").execute(); dbconnection.release(); mockConcurrent(pool); Thread.sleep(1000); mockConcurrent(pool); Thread.sleep(60); } catch (Exception e) { e.printStackTrace(); } finally { dbconnection.release(); } } } /** * 模拟多线程并发访问数据库,并发插入 10行数据 * @param pool */ public static void mockConcurrent(DBConnectionPool pool) { for (int index = 0; index < 10; ++ index) { final int value = index; Thread thread = new Thread() { public void run() { DBConnection dbconnection = pool.getDBConnectionQuietly(); if (null != dbconnection) { try { // 插入数据 PreparedStatement statement = dbconnection.getConnection().prepareStatement("insert into test_pool(tp_value) values(?);"); statement.setInt(1, value); statement.execute(); StringBuffer msg = new StringBuffer(); msg.append("dbconnection index=").append(dbconnection.getIndex()) .append(", insert=").append(value) .append(", time=").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date())); System.out.println(msg.toString()); } catch (Exception e) { e.printStackTrace(); } finally { dbconnection.release(); } } } }; thread.start(); } } }
?运行 DBConnectionPoolTest.java,控制台输出:
?
dbconnection index=1, insert=0, time=2014-11-29 11:20:46 901
dbconnection index=2, insert=2, time=2014-11-29 11:20:46 917
dbconnection index=3, insert=8, time=2014-11-29 11:20:46 917
dbconnection index=2, insert=1, time=2014-11-29 11:20:46 960
dbconnection index=1, insert=4, time=2014-11-29 11:20:46 960
dbconnection index=3, insert=6, time=2014-11-29 11:20:46 984
dbconnection index=2, insert=7, time=2014-11-29 11:20:47 008
dbconnection index=1, insert=9, time=2014-11-29 11:20:47 008
【dbconnection-3】idle timeout.
dbconnection index=1, insert=3, time=2014-11-29 11:20:47 092
dbconnection index=2, insert=5, time=2014-11-29 11:20:47 142
【dbconnection-1】idle timeout.
【dbconnection-2】idle timeout.
dbconnection index=2, insert=1, time=2014-11-29 11:20:47 907
dbconnection index=1, insert=0, time=2014-11-29 11:20:47 929
dbconnection index=3, insert=3, time=2014-11-29 11:20:47 929
dbconnection index=2, insert=4, time=2014-11-29 11:20:47 948
dbconnection index=1, insert=5, time=2014-11-29 11:20:47 982
dbconnection index=3, insert=8, time=2014-11-29 11:20:47 982
?
has closed all!
?
?
原文:http://aijuans.iteye.com/blog/2161821