Java的JDBC数据库连接池实现方法

开发 后端
虽然J2EE程序员一般都有现成的应用服务器所带的JDBC数据库连接池,不过对于开发一般的Java Application、 Applet或者JSP、velocity时,我们可用的JDBC数据库连接池并不多,并且一般性能都不好。

Java程序员都很羡慕Windows ADO ,只需要new Connection 就可以直接从数据库连接池中返回Connection。并且 ADO Connection 是线程安全的,多个线程可以共用一个Connection,所以ASP程序一般都把getConnection 放在 Global.asa 文件中,在 IIS 启动时建立数据库连接。ADO 的Connection 和Result 都有很好的缓冲,并且很容易使用。

其实我们可以自己写一个JDBC数据库连接池。

写JDBC connection pool 的注意事项有:

1. 有一个简单的函数从连接池中得到一个 Connection。

2. close 函数必须将connection 放回 数据库连接池。

3. 当数据库连接池中没有空闲的connection,数据库连接池必须能够自动增加connection 个数。

4. 当数据库连接池中的connection 个数在某一个特别的时间变得很大,但是以后很长时间只用其中一小部分,应该可以自动将多余的connection 关闭掉。

5. 如果可能,应该提供debug 信息报告没有关闭的new Connection 。

如果要new Connection 就可以直接从数据库连接池中返回Connection, 可以这样写( Mediator pattern ) (以下代码中使用了中文全角空格):

public class EasyConnection implements java.sql.Connection{  
  private Connection m_delegate = null;  
  public EasyConnection(){  
    m_delegate = getConnectionFromPool();  
  }  
 public void close(){  
    putConnectionBackToPool(m_delegate);  
  }  
  public PreparedStatement prepareStatement(String sql) throws SQLException{  
    m_delegate.prepareStatement(sql);  
  }  
  //...... other method  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

看来并不难。不过不建议这种写法,因为应该尽量避免使用Java Interface, 关于Java Interface 的缺点我另外再写文章讨论。大家关注的是Connection Pool 的实现方法。下面给出一种实现方法。

import java.sql.*;  
import java.lang.reflect.*;  
import java.util.*;  
import java.io.*;  
 
public class SimpleConnetionPool {  
  private static LinkedList m_notUsedConnection = new LinkedList();  
  private static HashSet m_usedUsedConnection = new HashSet();  
  private static String m_url = "";  
  private static String m_user = "";  
  private static String m_password = "";  
  static final boolean DEBUG = true;  
  static private long m_lastClearClosedConnection = System.currentTimeMillis();  
  public static long CHECK_CLOSED_CONNECTION_TIME = 4 * 60 * 60 * 1000//4 hours  
 
  static {  
    initDriver();  
  }  
 
  private SimpleConnetionPool() {  
  }  
 
  private static void initDriver() {  
    Driver driver = null;  
    //load mysql driver  
    try {  
      driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();  
      installDriver(driver);  
    } catch (Exception e) {  
    }  
 
    //load postgresql driver  
    try {  
      driver = (Driver) Class.forName("org.postgresql.Driver").newInstance();  
      installDriver(driver);  
    } catch (Exception e) {  
    }  
  }  
 
  public static void installDriver(Driver driver) {  
    try {  
      DriverManager.registerDriver(driver);  
    } catch (Exception e) {  
      e.printStackTrace();  
    }  
  }  
 
 
  public static synchronized Connection getConnection() {  
    clearClosedConnection();  
    while (m_notUsedConnection.size() > 0) {  
      try {  
        ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection.removeFirst();  
        if (wrapper.connection.isClosed()) {  
          continue;  
        }  
        m_usedUsedConnection.add(wrapper);  
        if (DEBUG) {  
          wrapper.debugInfo = new Throwable("Connection initial statement");  
        }  
        return wrapper.connection;  
      } catch (Exception e) {  
      }  
    }  
    int newCount = getIncreasingConnectionCount();  
    LinkedList list = new LinkedList();  
    ConnectionWrapper wrapper = null;  
    for (int i = 0; i < newCount; i++) {  
      wrapper = getNewConnection();  
      if (wrapper != null) {  
        list.add(wrapper);  
      }  
    }  
    if (list.size() == 0) {  
      return null;  
    }  
    wrapper = (ConnectionWrapper) list.removeFirst();  
    m_usedUsedConnection.add(wrapper);  
 
    m_notUsedConnection.addAll(list);  
    list.clear();  
 
    return wrapper.connection;  
  }  
 
  private static ConnectionWrapper getNewConnection() {  
    try {  
      Connection con = DriverManager.getConnection(m_url, m_user, m_password);  
      ConnectionWrapper wrapper = new ConnectionWrapper(con);  
      return wrapper;  
    } catch (Exception e) {  
      e.printStackTrace();  
    }  
    return null;  
  }  
 
  static synchronized void pushConnectionBackToPool(ConnectionWrapper con) {  
    boolean exist = m_usedUsedConnection.remove(con);  
    if (exist) {  
      m_notUsedConnection.addLast(con);  
    }  
  }  
 
  public static int close() {  
    int count = 0;  
 
    Iterator iterator = m_notUsedConnection.iterator();  
    while (iterator.hasNext()) {  
      try {  
        ( (ConnectionWrapper) iterator.next()).close();  
        count++;  
      } catch (Exception e) {  
      }  
    }  
    m_notUsedConnection.clear();  
 
    iterator = m_usedUsedConnection.iterator();  
    while (iterator.hasNext()) {  
      try {  
        ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();  
        wrapper.close();  
        if (DEBUG) {  
          wrapper.debugInfo.printStackTrace();  
        }  
        count++;  
      } catch (Exception e) {  
      }  
    }  
    m_usedUsedConnection.clear();  
 
    return count;  
  }  
 
  private static void clearClosedConnection() {  
    long time = System.currentTimeMillis();  
    //sometimes user change system time,just return  
    if (time < m_lastClearClosedConnection) {  
      time = m_lastClearClosedConnection;  
      return;  
    }  
    //no need check very often  
    if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {  
      return;  
    }  
    m_lastClearClosedConnection = time;  
 
    //begin check  
    Iterator iterator = m_notUsedConnection.iterator();  
    while (iterator.hasNext()) {  
      ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();  
      try {  
        if (wrapper.connection.isClosed()) {  
          iterator.remove();  
        }  
      } catch (Exception e) {  
        iterator.remove();  
        if (DEBUG) {  
          System.out.println("connection is closed, this connection initial StackTrace");  
          wrapper.debugInfo.printStackTrace();  
        }  
      }  
    }  
 
    //make connection pool size smaller if too big  
    int decrease = getDecreasingConnectionCount();  
    if (m_notUsedConnection.size() < decrease) {  
      return;  
    }  
 
    while (decrease-- > 0) {  
      ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection.removeFirst();  
      try {  
        wrapper.connection.close();  
      } catch (Exception e) {  
      }  
    }  
  }  
 
  /**  
   * get increasing connection count, not just add 1 connection  
   * @return count  
   */ 
  public static int getIncreasingConnectionCount() {  
    int count = 1;  
    int current = getConnectionCount();  
    count = current / 4;  
    if (count < 1) {  
      count = 1;  
    }  
    return count;  
  }  
 
  /**  
   * get decreasing connection count, not just remove 1 connection  
   * @return count  
   */ 
  public static int getDecreasingConnectionCount() {  
    int count = 0;  
    int current = getConnectionCount();  
    if (current < 10) {  
      return 0;  
    }  
    return current / 3;  
  }  
 
  public synchronized static void printDebugMsg() {  
    printDebugMsg(System.out);  
  }  
 
  public synchronized static void printDebugMsg(PrintStream out) {  
    if (DEBUG == false) {  
      return;  
    }  
    StringBuffer msg = new StringBuffer();  
    msg.append("debug message in " + SimpleConnetionPool.class.getName());  
    msg.append("\r\n");  
    msg.append("total count is connection pool: " + getConnectionCount());  
    msg.append("\r\n");  
    msg.append("not used connection count: " + getNotUsedConnectionCount());  
    msg.append("\r\n");  
    msg.append("used connection, count: " + getUsedConnectionCount());  
    out.println(msg);  
    Iterator iterator = m_usedUsedConnection.iterator();  
    while (iterator.hasNext()) {  
      ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();  
      wrapper.debugInfo.printStackTrace(out);  
    }  
    out.println();  
  }  
 
  public static synchronized int getNotUsedConnectionCount() {  
    return m_notUsedConnection.size();  
  }  
 
  public static synchronized int getUsedConnectionCount() {  
    return m_usedUsedConnection.size();  
  }  
 
  public static synchronized int getConnectionCount() {  
    return m_notUsedConnection.size() + m_usedUsedConnection.size();  
  }  
 
  public static String getUrl() {  
    return m_url;  
  }  
 
  public static void setUrl(String url) {  
    if (url == null) {  
      return;  
    }  
    m_url = url.trim();  
  }  
 
  public static String getUser() {  
    return m_user;  
  }  
 
  public static void setUser(String user) {  
    if (user == null) {  
      return;  
    }  
    m_user = user.trim();  
  }  
 
  public static String getPassword() {  
    return m_password;  
  }  
 
  public static void setPassword(String password) {  
    if (password == null) {  
      return;  
    }  
    m_password = password.trim();  
  }  
 
}  
 
class ConnectionWrapper implements InvocationHandler {  
  private final static String CLOSE_METHOD_NAME = "close";  
  public Connection connection = null;  
  private Connection m_originConnection = null;  
  public long lastAccessTime = System.currentTimeMillis();  
  Throwable debugInfo = new Throwable("Connection initial statement");  
 
  ConnectionWrapper(Connection con) {  
    this.connection = (Connection) Proxy.newProxyInstance(  
      con.getClass().getClassLoader(),  
      con.getClass().getInterfaces(), this);  
    m_originConnection = con;  
  }  
 
  void close() throws SQLException {  
    m_originConnection.close();  
  }  
 
  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {  
    Object obj = null;  
    if (CLOSE_METHOD_NAME.equals(m.getName())) {  
      SimpleConnetionPool.pushConnectionBackToPool(this);  
    }  
    else {  
      obj = m.invoke(m_originConnection, args);  
    }  
    lastAccessTime = System.currentTimeMillis();  
    return obj;  
  }  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.

使用方法

public class TestConnectionPool{  
  public static void main(String[] args) {  
    SimpleConnetionPool.setUrl(DBTools.getDatabaseUrl());  
    SimpleConnetionPool.setUser(DBTools.getDatabaseUserName());  
    SimpleConnetionPool.setPassword(DBTools.getDatabasePassword());  
 
    Connection con = SimpleConnetionPool.getConnection();  
    Connection con1 = SimpleConnetionPool.getConnection();  
    Connection con2 = SimpleConnetionPool.getConnection();  
 
    //do something with con ...  
 
    try {  
      con.close();  
    } catch (Exception e) {}  
 
    try {  
      con1.close();  
    } catch (Exception e) {}  
 
    try {  
      con2.close();  
    } catch (Exception e) {}  
 
    con = SimpleConnetionPool.getConnection();  
    con1 = SimpleConnetionPool.getConnection();  
    try {  
      con1.close();  
    } catch (Exception e) {}  
 
    con2 = SimpleConnetionPool.getConnection();  
    SimpleConnetionPool.printDebugMsg();  
 
  }  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

运行测试程序后打印JDBC数据库连接池中Connection状态,以及正在使用的没有关闭Connection信息。

【编辑推荐】

  1. 谈谈优化JDBC数据库编程
  2. 实例说明对MySQL的JDBC连接设置
  3. 浅谈如何利用JSP网页中JDBC代码连接MySQL
  4. 浅谈JDBC代码如何重复使用
  5. 如何进行Jython数据库插入(JDBC)
责任编辑:彭凡 来源: 百度空间
相关推荐

2010-10-26 16:15:33

连接Oracle数据库

2009-06-24 07:53:47

Hibernate数据

2010-12-10 16:19:04

JDBC数据库连接池DDLSQLJ存储过程

2010-03-18 15:09:15

python数据库连接

2019-11-27 10:31:51

数据库连接池内存

2017-06-22 14:13:07

PythonMySQLpymysqlpool

2009-07-22 14:30:53

JDBC连接池

2018-10-10 14:27:34

数据库连接池MySQL

2009-06-16 09:25:31

JBoss配置

2011-05-19 09:53:33

数据库连接池

2018-01-03 14:32:32

2011-07-04 10:17:38

JDBC

2011-05-26 09:27:59

JDBC连接数据库

2019-12-30 15:30:13

连接池请求PHP

2025-02-07 12:11:52

2021-08-12 06:52:01

.NET数据库连接池

2020-04-30 14:38:51

数据库连接池线程

2009-07-03 17:37:54

JSP数据库

2009-01-15 09:02:27

JMXJBossJMX监控

2009-07-29 09:33:14

ASP.NET数据库连
点赞
收藏

51CTO技术栈公众号