本文共 9700 字,大约阅读时间需要 32 分钟。
关键字: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;//4hoursstatic{
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信息。
转载地址:http://ookni.baihongyu.com/