`

jdbc资源池

阅读更多
Java 的JDBC 数据库连接池实现方法
http://www.dayoo.com/http://www.dayoo.com/ 2010-05-21 11:55来源: 信息报 发表评论 (0)
    关键字: Java, JDBC, Connection Pool, Database, 数据库连接池, sourcecode

  虽然 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

}

    看来并不难。不过不建议这种写法,因为应该尽量避免使用 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) {
    Class interfaces = {java.sql.Connection.class};
    this.connection = (Connection) Proxy.newProxyInstance(
      con.getClass.getClassLoader,
      interfaces, 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;
  }
}

    使用方法

    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;

  }
}

    运行测试程序后打印连接池中 Connection 状态, 以及正在使用的没有关闭 Connection 信息。
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Tongweb5中配置JDBC连接池

    在企业级Java应用程序开发中,使用连接池管理数据库连接是一种常见的优化策略,它能有效提高系统性能并降低资源消耗。Tongweb5是一款基于Java的Web应用服务器,它支持配置JDBC连接池来管理数据库连接。本文将详细...

    jdbc连接池配置(优化连接速度)

    总的来说,理解JDBC连接池的工作机制,并结合实际应用需求进行配置优化,可以显著提升数据库访问速度,降低系统资源消耗,提高应用的稳定性和性能。在开发过程中,选择合适的连接池并持续监控和调优是至关重要的。

    jdbc连接池资源声明

    在深入探讨“jdbc连接池资源声明”的核心概念之前,我们首先需要理解JDBC(Java Database Connectivity)的基本原理及其在企业级应用中的重要性。JDBC是一种用于执行SQL语句的标准Java API,它允许Java应用程序与...

    完美的java jdbc连接池实例

    总之,这个"完美的Java JDBC连接池实例"提供了灵活、高效的数据源管理方案,无论是在小型应用还是大型企业级系统中,都能显著提升数据库操作的性能,降低资源消耗。同时,其兼容多种数据库的能力使得迁移和扩展变得...

    JDBC连接池(通用basedao)可直接用的模板

    在Java开发中,数据库操作是不可或缺的一部分,而JDBC连接池是提高数据库访问效率、优化系统资源使用的重要技术。本文将深入探讨JDBC连接池的概念、工作原理,并以"通用basedao"模板为例,讲解如何在实际项目中应用...

    简单的jdbc连接池类

    本示例中的"简单的jdbc连接池类"实现了一个基本的数据库连接池功能,非常适合初学者理解和实践。 首先,我们来理解`jdbc`。JDBC(Java Database Connectivity)是Java语言用来与各种数据库进行交互的一种标准接口。...

    JDBC连接池BoneCP_Demo

    **JDBC连接池BoneCP_Demo详解** 在Java开发中,数据库操作是不可或缺的一部分,而JDBC(Java Database Connectivity)是Java与数据库交互的标准接口。然而,直接使用JDBC进行数据库连接管理可能会导致资源浪费,...

    java JDBC连接池

    Java JDBC连接池是一种高效管理数据库连接的技术,它允许应用程序重复使用已经建立的数据库连接,从而减少频繁创建和关闭连接带来的开销。在大型系统中,尤其是高并发环境下,使用连接池能够显著提升性能并降低资源...

    jdbc连接池

    JDBC(Java Database Connectivity)连接池就是为了解决这个问题而诞生的一种技术。它允许开发者在不频繁创建和销毁数据库连接的情况下,有效地复用已存在的连接,从而减少系统开销,提高应用程序的响应速度。 标题...

    Java jdbc数据库连接池总结

    Java JDBC 数据库连接池...Java JDBC 数据库连接池技术可以解决频繁的数据库连接操作对系统资源的占用,提高系统的性能和可靠性。同时,连接池技术也可以和其它技术结合使用,例如 EJB 技术,实现高效的数据库访问。

    完美的java jdbc连接池实例.zip

    而JDBC连接池是一种管理资源的技术,它能有效地管理和复用数据库连接,提高系统性能并减少系统资源的消耗。在Java应用中,常见的连接池实现有DBCP、C3P0、HikariCP、Druid等。 标题"完美的java jdbc连接池实例.zip...

    Jdbc连接池

    JDBC连接池是一种资源管理机制,它允许应用程序重复使用已建立的数据库连接,而不是每次需要时都创建新的连接。这显著提高了性能,减少了系统资源的消耗,并有助于避免由于过多的数据库连接导致的问题。在Tomcat早期...

    jdbc连接池dbcp工具包

    Java数据库连接池(JDBC Connection Pool)是Java应用程序管理数据库连接的一种机制,它能够有效地提高数据库访问效率并优化资源使用。DBCP(Jakarta DBCP,又称为Apache Commons DBCP)是Apache软件基金会提供的一...

    JDBC连接池使用工具 C3P0 连接池 and druid-1.0.9

    JDBC(Java Database Connectivity)是Java与数据库交互的标准接口,但频繁地打开和关闭数据库连接会消耗大量资源。为了解决这个问题,引入了连接池技术,其中C3P0和Druid是两个常用的连接池实现。 **C3P0连接池** ...

    HikariCP JDBC连接池 v3.4.5.zip

    HikariCP是一款高效、高性能的Java JDBC连接池,它被设计为替代传统连接池如C3P0和DBCP,以提供更快、更稳定的数据访问性能。在HikariCP v3.4.5这个版本中,我们可以深入探讨其在数据库连接管理、性能优化以及配置...

    jdbc 连接池

    C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。C3P0的主要特点包括: 1. **自动管理数据库连接**:C3P0会自动创建、配置和管理数据库连接,避免了频繁创建和销毁连接...

    jdbc连接池c3p0工具包

    **jdbc连接池c3p0工具包** 在Java开发中,数据库操作是常见的任务,而JDBC(Java Database Connectivity)是Java与数据库交互的标准接口。然而,直接使用JDBC进行数据库连接可能会导致性能问题,因为每次连接和断开...

    线程安全的jdbc连接池

    JDBC连接池(Java Database Connectivity Connection Pool)是数据库资源的复用机制,它预先创建了一定数量的数据库连接,当多个线程需要同时访问数据库时,可以从池中获取已建立的连接,使用完毕后再归还,避免了...

    BeeCP一款小型JDBC连接池组件

    BeeCP,一个小型JDBC连接池:高性能,轻量级代码和良好的稳定性。支持主要流行的数据库驱动程序。支持 XAConnection/JTA。池功能:CAS、单连接缓存、队列复用、非移动等待自旋、异步加法、安全关闭、Web 监控等。...

    关于JDBC连接池的java类

    总的来说,JDBC连接池是Java应用与数据库交互时必不可少的一个组件,它提升了应用的效率,降低了资源消耗,为大型系统的稳定运行提供了保障。通过使用这个java类,开发者可以更轻松地在项目中集成和使用连接池功能。

Global site tag (gtag.js) - Google Analytics