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

关键字:Java,JDBC,ConnectionPool,Database,数据库连接池,sourcecode

  虽然J2EE程序员一般都有现成的应用服务器所带的JDBC数据库连接池,不过对于开发一般的JavaApplication、Applet或者JSP、velocity时,我们可用的JDBC数据库连接池并不多,并且一般性能都不好。Java程序员都很羡慕WindowsADO,只需要newConnection就可以直接从数据库连接池中返回Connection。并且ADOConnection是线程安全的,多个线程可以共用一个Connection,所以ASP程序一般都把getConnection放在Global.asa文件中,在IIS启动时建立数据库连接。ADO的Connection和Result都有很好的缓冲,并且很容易使用。

其实我们可以自己写一个JDBC数据库连接池。写JDBCconnectionpool的注意事项有:

1.有一个简单的函数从连接池中得到一个Connection。
2.close函数必须将connection放回数据库连接池。
3.当数据库连接池中没有空闲的connection,数据库连接池必须能够自动增加connection个数。
4.当数据库连接池中的connection个数在某一个特别的时间变得很大,但是以后很长时间只用其中一小部分,应该可以自动将多余的connection关闭掉。
5.如果可能,应该提供debug信息报告没有关闭的newConnection。

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

publicclassEasyConnectionimplementsjava.sql.Connection{
  privateConnectionm_delegate=null;

  publicEasyConnection(){
    m_delegate=getConnectionFromPool();
  }

  publicvoidclose(){
    putConnectionBackToPool(m_delegate);
  }

  publicPreparedStatementprepareStatement(Stringsql)throwsSQLException{
    m_delegate.prepareStatement(sql);
  }

  //......othermethod

}

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

importjava.sql.*;
importjava.lang.reflect.*;
importjava.util.*;
importjava.io.*;

publicclassSimpleConnetionPool{
  privatestaticLinkedListm_notUsedConnection=newLinkedList();
  privatestaticHashSetm_usedUsedConnection=newHashSet();
  privatestaticStringm_url="";
  privatestaticStringm_user="";
  privatestaticStringm_password="";
  staticfinalbooleanDEBUG=true;
  staticprivatelongm_lastClearClosedConnection=System.currentTimeMillis();
  publicstaticlongCHECK_CLOSED_CONNECTION_TIME=4*60*60*1000;//4hours

  static{
    initDriver();
  }

  privateSimpleConnetionPool(){
  }

  privatestaticvoidinitDriver(){
    Driverdriver=null;
    //loadmysqldriver
    try{
      driver=(Driver)Class.forName("com.mysql.jdbc.Driver").newInstance();
      installDriver(driver);
    }catch(Exceptione){
    }

    //loadpostgresqldriver
    try{
      driver=(Driver)Class.forName("org.postgresql.Driver").newInstance();
      installDriver(driver);
    }catch(Exceptione){
    }
  }

  publicstaticvoidinstallDriver(Driverdriver){
    try{
      DriverManager.registerDriver(driver);
    }catch(Exceptione){
      e.printStackTrace();
    }
  }


  publicstaticsynchronizedConnectiongetConnection(){
    clearClosedConnection();
    while(m_notUsedConnection.size()>0){
      try{
        ConnectionWrapperwrapper=(ConnectionWrapper)m_notUsedConnection.removeFirst();
        if(wrapper.connection.isClosed()){
          continue;
        }
        m_usedUsedConnection.add(wrapper);
        if(DEBUG){
          wrapper.debugInfo=newThrowable("Connectioninitialstatement");
        }
        returnwrapper.connection;
      }catch(Exceptione){
      }
    }
    intnewCount=getIncreasingConnectionCount();
    LinkedListlist=newLinkedList();
    ConnectionWrapperwrapper=null;
    for(inti=0;i<newCount;i++){
      wrapper=getNewConnection();
      if(wrapper!=null){
        list.add(wrapper);
      }
    }
    if(list.size()==0){
      returnnull;
    }
    wrapper=(ConnectionWrapper)list.removeFirst();
    m_usedUsedConnection.add(wrapper);

    m_notUsedConnection.addAll(list);
    list.clear();

    returnwrapper.connection;
  }

  privatestaticConnectionWrappergetNewConnection(){
    try{
      Connectioncon=DriverManager.getConnection(m_url,m_user,m_password);
      ConnectionWrapperwrapper=newConnectionWrapper(con);
      returnwrapper;
    }catch(Exceptione){
      e.printStackTrace();
    }
    returnnull;
  }

  staticsynchronizedvoidpushConnectionBackToPool(ConnectionWrappercon){
    booleanexist=m_usedUsedConnection.remove(con);
    if(exist){
      m_notUsedConnection.addLast(con);
    }
  }

  publicstaticintclose(){
    intcount=0;

    Iteratoriterator=m_notUsedConnection.iterator();
    while(iterator.hasNext()){
      try{
        ((ConnectionWrapper)iterator.next()).close();
        count++;
      }catch(Exceptione){
      }
    }
    m_notUsedConnection.clear();

    iterator=m_usedUsedConnection.iterator();
    while(iterator.hasNext()){
      try{
        ConnectionWrapperwrapper=(ConnectionWrapper)iterator.next();
        wrapper.close();
        if(DEBUG){
          wrapper.debugInfo.printStackTrace();
        }
        count++;
      }catch(Exceptione){
      }
    }
    m_usedUsedConnection.clear();

    returncount;
  }

  privatestaticvoidclearClosedConnection(){
    longtime=System.currentTimeMillis();
    //sometimesuserchangesystemtime,justreturn
    if(time<m_lastClearClosedConnection){
      time=m_lastClearClosedConnection;
      return;
    }
    //noneedcheckveryoften
    if(time-m_lastClearClosedConnection<CHECK_CLOSED_CONNECTION_TIME){
      return;
    }
    m_lastClearClosedConnection=time;

    //begincheck
    Iteratoriterator=m_notUsedConnection.iterator();
    while(iterator.hasNext()){
      ConnectionWrapperwrapper=(ConnectionWrapper)iterator.next();
      try{
        if(wrapper.connection.isClosed()){
          iterator.remove();
        }
      }catch(Exceptione){
        iterator.remove();
        if(DEBUG){
          System.out.println("connectionisclosed,thisconnectioninitialStackTrace");
          wrapper.debugInfo.printStackTrace();
        }
      }
    }

    //makeconnectionpoolsizesmalleriftoobig
    intdecrease=getDecreasingConnectionCount();
    if(m_notUsedConnection.size()<decrease){
      return;
    }

    while(decrease-->0){
      ConnectionWrapperwrapper=(ConnectionWrapper)m_notUsedConnection.removeFirst();
      try{
        wrapper.connection.close();
      }catch(Exceptione){
      }
    }
  }

  /**
  *getincreasingconnectioncount,notjustadd1connection
  *@returncount
  */
  publicstaticintgetIncreasingConnectionCount(){
    intcount=1;
    intcurrent=getConnectionCount();
    count=current/4;
    if(count<1){
      count=1;
    }
    returncount;
  }

  /**
  *getdecreasingconnectioncount,notjustremove1connection
  *@returncount
  */
  publicstaticintgetDecreasingConnectionCount(){
    intcount=0;
    intcurrent=getConnectionCount();
    if(current<10){
      return0;
    }
    returncurrent/3;
  }

  publicsynchronizedstaticvoidprintDebugMsg(){
    printDebugMsg(System.out);
  }

  publicsynchronizedstaticvoidprintDebugMsg(PrintStreamout){
    if(DEBUG==false){
      return;
    }
    StringBuffermsg=newStringBuffer();
    msg.append("debugmessagein"+SimpleConnetionPool.class.getName());
    msg.append("/r/n");
    msg.append("totalcountisconnectionpool:"+getConnectionCount());
    msg.append("/r/n");
    msg.append("notusedconnectioncount:"+getNotUsedConnectionCount());
    msg.append("/r/n");
    msg.append("usedconnection,count:"+getUsedConnectionCount());
    out.println(msg);
    Iteratoriterator=m_usedUsedConnection.iterator();
    while(iterator.hasNext()){
      ConnectionWrapperwrapper=(ConnectionWrapper)iterator.next();
      wrapper.debugInfo.printStackTrace(out);
    }
    out.println();
  }

  publicstaticsynchronizedintgetNotUsedConnectionCount(){
    returnm_notUsedConnection.size();
  }

  publicstaticsynchronizedintgetUsedConnectionCount(){
    returnm_usedUsedConnection.size();
  }

  publicstaticsynchronizedintgetConnectionCount(){
    returnm_notUsedConnection.size()+m_usedUsedConnection.size();
  }

  publicstaticStringgetUrl(){
    returnm_url;
  }

  publicstaticvoidsetUrl(Stringurl){
    if(url==null){
      return;
    }
    m_url=url.trim();
  }

  publicstaticStringgetUser(){
    returnm_user;
  }

  publicstaticvoidsetUser(Stringuser){
    if(user==null){
      return;
    }
    m_user=user.trim();
  }

  publicstaticStringgetPassword(){
    returnm_password;
  }

  publicstaticvoidsetPassword(Stringpassword){
    if(password==null){
      return;
    }
    m_password=password.trim();
  }

}

classConnectionWrapperimplementsInvocationHandler{
  privatefinalstaticStringCLOSE_METHOD_NAME="close";
  publicConnectionconnection=null;
  privateConnectionm_originConnection=null;
  publiclonglastAccessTime=System.currentTimeMillis();
  ThrowabledebugInfo=newThrowable("Connectioninitialstatement");

  ConnectionWrapper(Connectioncon){
    Class[]interfaces={java.sql.Connection.class};
    this.connection=(Connection)Proxy.newProxyInstance(
      con.getClass().getClassLoader(),
      interfaces,this);
    m_originConnection=con;
  }

  voidclose()throwsSQLException{
    m_originConnection.close();
  }

  publicObjectinvoke(Objectproxy,Methodm,Object[]args)throwsThrowable{
    Objectobj=null;
    if(CLOSE_METHOD_NAME.equals(m.getName())){
      SimpleConnetionPool.pushConnectionBackToPool(this);
    }
    else{
      obj=m.invoke(m_originConnection,args);
    }
    lastAccessTime=System.currentTimeMillis();
    returnobj;
  }
}

使用方法

publicclassTestConnectionPool{
  publicstaticvoidmain(String[]args){
    SimpleConnetionPool.setUrl(DBTools.getDatabaseUrl());
    SimpleConnetionPool.setUser(DBTools.getDatabaseUserName());
    SimpleConnetionPool.setPassword(DBTools.getDatabasePassword());

    Connectioncon=SimpleConnetionPool.getConnection();
    Connectioncon1=SimpleConnetionPool.getConnection();
    Connectioncon2=SimpleConnetionPool.getConnection();

    //dosomethingwithcon...

    try{
      con.close();
    }catch(Exceptione){}

    try{
      con1.close();
    }catch(Exceptione){}

    try{
      con2.close();
    }catch(Exceptione){}

    con=SimpleConnetionPool.getConnection();
    con1=SimpleConnetionPool.getConnection();
    try{
      con1.close();
    }catch(Exceptione){}

    con2=SimpleConnetionPool.getConnection();
    SimpleConnetionPool.printDebugMsg();

  }
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值