自己写的数据库连接池(二)

原创 2004年08月24日 04:20:00
**
 * Statement的自封装,屏蔽了getResultSet,executeQuery,getGeneratedKeys方法 返回自己的接管类
 * 目的适记录SQl的动作和设置相应连接最后活动时间。
 * @author Liudong
 */




package com.drsl.db;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.lang.reflect.*;
import sun.jdbc.odbc.*;
public class StatementObject implements InvocationHandler{
    
    private Statement stm=null;
    private    Statement stm_proxy=null;
    
    private final static String GETRESULTSET_METHOD_NAME = "getResultSet";
    private final static String EXECUTEQUERY_METHOD_NAME = "executeQuery";
    private final static String GETGENERATEDKEYS_METHOD_NAME = "getGeneratedKeys";
    
    private ResultSetObject rso=null;

    public StatementObject(Statement stm){
        this.stm=stm;
    }
    
    public Statement getStatement(){
        if(stm_proxy==null){
            ClassLoader classloader=stm.getClass().getClassLoader();
            Class[] interfaces = stm.getClass().getInterfaces(); 
            
            if(interfaces==null||interfaces.length==0){ 
                interfaces = new Class[1]; 
                interfaces[0] = Statement.class
            }
            
            try{
                
                stm_proxy= (Statement)Proxy.newProxyInstance(classloader,interfaces,this);
                
            }catch(NullPointerException e){
                log(e,"StatementObject getStatement()--error");
            }
            if(stm_proxy!=null)
                log("StatementObject getStatement()--success");
        }
        return stm_proxy;
    }
    
    public Object invoke(Object proxy, Method m, Object[] args)    throws Throwable 
    {
        Object obj = null;
        log("StatementObject--invoke:Method: /""+m.getName()+"/"");
         
        //判断是否调用了getResultSet or executeQuery or getGeneratedKeys
        //是就截获
        if(GETRESULTSET_METHOD_NAME.equals(m.getName()) 
            || EXECUTEQUERY_METHOD_NAME.equals(m.getName())
                || GETGENERATEDKEYS_METHOD_NAME.equals(m.getName())){
                    
            ResultSet rs=(ResultSet)m.invoke(stm, args);
            
            if(rs!=null && rso==null){
                rso=new ResultSetObject(rs);
                obj=rso.getResultSet();
            }else if(rso!=null)
                obj=rso.getResultSet();
            else    
                log("StatementObject--invoke:Method: /""+m.getName()+"/"--失败");
            
        }else{
            obj = m.invoke(stm, args);    
        }
        
        //设置最后一次访问时间,以便及时清除超时的连接
        setLastAccessTime( new Date().getTime());
        return obj;
    }
    /**
    * 将文本信息写入日志文件
    */

    private void log(String msg) {
        ConnectionManager.log(msg);
    }
    
    /**
    * 将文本信息与异常写入日志文件
    */

    private void log(Throwable e, String msg) {
        ConnectionManager.log(e,msg);
    }
    
    //设置最后一次访问时间
    private void setLastAccessTime(long ltime){
        ConnectionObject.setLastAccessTime(ltime);
    }

}
/////////////////////////////////////////////////////////////////////////////////


/**
 * PreparedStatement 的自封装,屏蔽了executeQuery方法 返回自己的接管类
 * 目的适记录SQl的动作和设置相应连接最后活动时间。
 * @author Liudong
 */


package com.drsl.db;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.lang.reflect.*;

public class PreparedStatementObject implements InvocationHandler{
    
    private PreparedStatement ps=null;
    private    PreparedStatement ps_proxy =null;
    
    private final static String EXECUTEQUERY_METHOD_NAME = "executeQuery";
    private ResultSetObject rso=null;

    
    PreparedStatementObject(PreparedStatement ps){
        this.ps=ps;
    }
    public PreparedStatement getPreparedStatement(){
        if(ps_proxy==null){
            ClassLoader classloader=ps.getClass().getClassLoader();
            Class[] interfaces = ps.getClass().getInterfaces(); 
            
            if(interfaces==null||interfaces.length==0){ 
                interfaces = new Class[1]; 
                interfaces[0] = PreparedStatement.class
            } 
    
            try{

                ps_proxy= (PreparedStatement) Proxy.newProxyInstance(classloader,interfaces,this);
                
            }catch(NullPointerException e){
                log(e,"PreparedStatementObject getPreparedStatement()--error");
            }
            if(ps_proxy!=null)
                log("PreparedStatementObject getPreparedStatement()--success");
        }
        return ps_proxy;
    }

    public Object invoke(Object proxy, Method m, Object[] args)    throws Throwable 
    {
        Object obj = null;
        log("PreparedStatementObject--invoke:Method: /""+m.getName()+"/"");
        
        //是否调用了executeQuery 如果是 则接管
        if(EXECUTEQUERY_METHOD_NAME.equals(m.getName())){
            
            ResultSet rs=(ResultSet)m.invoke(ps, args);
            if(rs!=null && rso==null){
                rso=new ResultSetObject(rs);
                obj=rso.getResultSet();
            }else if(rso!=null)
                obj=rso.getResultSet();
            else
                log("PreparedStatementObject--invoke:Method: /""+m.getName()+"/"--失败");
        }else{
            obj = m.invoke(ps, args);
        }
        
        obj = m.invoke(ps, args);    
        //设置最后一次访问时间,以便及时清除超时的连接
        setLastAccessTime( new Date().getTime());
        return obj;
    }
        /**
    * 将文本信息写入日志文件
    */

    private void log(String msg) {
        ConnectionManager.log(msg);
    }
    
    /**
    * 将文本信息与异常写入日志文件
    */

    private void log(Throwable e, String msg) {
        ConnectionManager.log(e,msg);
    }
    //设置最后一次访问时间
    private void setLastAccessTime(long ltime){
        ConnectionObject.setLastAccessTime(ltime);
    }
}


////////////////////////////////////////////////////////////////////////

/**
 * Statement的自封装,屏蔽了getStatement方法 返回自己的接管类
 * 目的适记录SQl的动作和设置相应连接最后活动时间。
 * @author Liudong
 */



package com.drsl.db;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.lang.reflect.*;

public class ResultSetObject implements InvocationHandler{
    
    private ResultSet rs=null;
    private    ResultSet rs_proxy =null;
    
    private final static String GETSTATEMENT_METHOD_NAME = "getStatement";
    private final static String GETMETADATA_METHOD_NAME = "getMetaData";
    
    private StatementObject stmo=null;
    private ResultSetMetaDataObject rsdmo=null;
    

    public ResultSetObject(ResultSet rs){
        this.rs=rs;
    }
    public ResultSet getResultSet(){
        
        if(rs_proxy==null){
            ClassLoader classloader=rs.getClass().getClassLoader();
            Class[] interfaces = rs.getClass().getInterfaces(); 
            
            if(interfaces==null||interfaces.length==0){ 
                interfaces = new Class[1]; 
                interfaces[0] = ResultSet.class
            }
            
            try{
                
                rs_proxy =(ResultSet)Proxy.newProxyInstance(classloader,interfaces,this);
                
            }catch(NullPointerException e){
                log(e,"ResultSetObject getResultSet()--error");
            }
            if(rs_proxy!=null)
                log("ResultSet getResultSet()--success");
        }
        return rs_proxy;
    }
    public Object invoke(Object proxy, Method m, Object[] args)    throws Throwable 
    {
        Object obj = null;
        
        log("ResultSetObject--invoke:Method: /""+m.getName()+"/"");
        //是否执行getStatement,返回Statement 的接管类
        if(GETSTATEMENT_METHOD_NAME.equals(m.getName())){
            
            Statement stm=(Statement)m.invoke(rs,args);
            if(stm!=null && stmo==null){
                stmo=new StatementObject(stm);
                obj=stmo.getStatement();
            }else if(stmo !=null)
                obj=stmo.getStatement();
            else
                log("ResultSetObject--invoke:Method: /""+m.getName()+"/"--失败");
            
        }else if(GETMETADATA_METHOD_NAME.equals(m.getName())){
            
            ResultSetMetaData rsdm=(ResultSetMetaData)m.invoke(rs, args);
            if(rsdm!=null && rsdmo==null){
                rsdmo=new ResultSetMetaDataObject(rsdm);
                obj = rsdmo.getMetaData();
            }else if(rsdmo!=null)
                obj = rsdmo.getMetaData();
            else
                log("ResultSetObject--invoke:Method: /""+m.getName()+"/"--失败");
            
        }else
            obj=m.invoke(rs,args);
        //设置最后一次访问时间,以便及时清除超时的连接
        setLastAccessTime( new Date().getTime());
        return obj;
    }
    /**
    * 将文本信息写入日志文件
    */

    private void log(String msg) {
        ConnectionManager.log(msg);
    }
    
    /**
    * 将文本信息与异常写入日志文件
    */

    private void log(Throwable e, String msg) {
        ConnectionManager.log(e,msg);
    }
    //设置最后一次访问时间
    private void setLastAccessTime(long ltime){
        ConnectionObject.setLastAccessTime(ltime);
    }
}
////////////////////////////////////////////////////////////////////////////


/**
 * ResultSetMetaData 的自封装,屏蔽了executeQuery方法 返回自己的接管类
 * 目的适记录SQl的动作和设置相应连接最后活动时间。
 * @author Liudong
 */


package com.drsl.db;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.lang.reflect.*;

public class ResultSetMetaDataObject implements InvocationHandler{
    
    private ResultSetMetaData rsmd=null;
    private    ResultSetMetaData rsmd_proxy =null;
    //
    
    public ResultSetMetaDataObject(ResultSetMetaData rsmd){
        this.rsmd=rsmd;
    }
    public ResultSetMetaData getMetaData(){
        if(rsmd_proxy==null){
            ClassLoader classloader=rsmd.getClass().getClassLoader();
            Class[] interfaces = rsmd.getClass().getInterfaces(); 
            
            if(interfaces==null||interfaces.length==0){ 
                interfaces = new Class[1]; 
                interfaces[0] = ResultSetMetaData.class
            } 
    
            try{

                rsmd_proxy= (ResultSetMetaData) Proxy.newProxyInstance(classloader,interfaces,this);
                
            }catch(NullPointerException e){
                log(e,"ResultSetMetaDataObject getPreparedStatement()--error");
            }
            if(rsmd_proxy!=null)
                log("ResultSetMetaDataObject getPreparedStatement()--success");
        }
        return rsmd_proxy;
    }

    public Object invoke(Object proxy, Method m, Object[] args)    throws Throwable 
    {
        Object obj = null;
        
        log("ResultSetMetaDataObject--invoke:Method: /""+m.getName()+"/"");
                
        obj = m.invoke(rsmd, args);    
        
        //设置最后一次访问时间,以便及时清除超时的连接
        
        setLastAccessTime( new Date().getTime());
        
        return obj;
    }
        /**
    * 将文本信息写入日志文件
    */

    private void log(String msg) {
        ConnectionManager.log(msg);
    }
    
    /**
    * 将文本信息与异常写入日志文件
    */

    private void log(Throwable e, String msg) {
        ConnectionManager.log(e,msg);
    }
    //设置最后一次访问时间
    private void setLastAccessTime(long ltime){
        ConnectionObject.setLastAccessTime(ltime);
    }
}
////////////////////////////////////////////////////////////////////////////////

/**
 * CallableStatement 的自封装,屏蔽了executeQuery getGeneratedKeys getMetaData 方法 返回自己的接管类
 * 目的是记录SQl的动作和设置相应连接最后活动时间。
 * @author Liudong
 */

package com.drsl.db;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.lang.reflect.*;


public class CallableStatementObject implements InvocationHandler{
    

    
    private CallableStatement cs=null;
    private    CallableStatement cs_proxy =null;
    
    private final static String EXECUTEQUERY_METHOD_NAME = "executeQuery";
    private final static String GETGENERATEDKEYS_METHOD_NAME = "getGeneratedKeys";
    private final static String GETMETADATA_METHOD_NAME = "getMetaData";
    
    private ResultSetObject rso=null;
    private ResultSetMetaDataObject rsmdo=null;
    
    CallableStatementObject(CallableStatement cs){
        this.cs=cs;
    }
    public CallableStatement getCallableStatement(){
        if(cs_proxy==null){
            ClassLoader classloader=cs.getClass().getClassLoader();
            Class[] interfaces = cs.getClass().getInterfaces(); 
            
            if(interfaces==null||interfaces.length==0){ 
                interfaces = new Class[1]; 
                interfaces[0] = CallableStatement.class
            } 
    
            try{

                cs_proxy= (CallableStatement) Proxy.newProxyInstance(classloader,interfaces,this);
                
            }catch(NullPointerException e){
                log(e,"CallableStatementObject getCallableStatement()--error");
            }
            if(cs_proxy!=null)
                log("CallableStatementObject getCallableStatement()--success");
        }
        return cs_proxy;
    }

    public Object invoke(Object proxy, Method m, Object[] args)    throws Throwable 
    {
        Object obj = null;
        log("CallableStatementObject--invoke:Method: /""+m.getName()+"/"");
        
        //是否调用了executeQuery || getGeneratedKeys 如果是 则接管
        if(EXECUTEQUERY_METHOD_NAME.equals(m.getName()) ||
           GETGENERATEDKEYS_METHOD_NAME.equals(m.getName())){
               
            ResultSet rs=(ResultSet)m.invoke(cs, args);
            if(rs!=null && rso==null){
                rso=new ResultSetObject(rs);
                obj=rso.getResultSet();
            }else if(rso!=null)
                obj=rso.getResultSet();
            else
                log("CallableStatementObject--invoke:Method: /""+m.getName()+"/"--失败");
        }else if(GETMETADATA_METHOD_NAME.equals(m.getName())){
            
            ResultSetMetaData rsmd=(ResultSetMetaData)m.invoke(cs, args);
            
            if(rsmd!=null && rsmdo==null){
                rsmdo=new ResultSetMetaDataObject(rsmd);
                obj=rsmdo.getMetaData();
            }else if(rsmdo!=null)
                obj=rsmdo.getMetaData();
            else
                log("CallableStatementObject--invoke:Method: /""+m.getName()+"/"--失败");
        }else
            obj = m.invoke(cs, args);    
        //设置最后一次访问时间,以便及时清除超时的连接
        setLastAccessTime( new Date().getTime());
        return obj;
    }
        /**
    * 将文本信息写入日志文件
    */

    private void log(String msg) {
        ConnectionManager.log(msg);
    }
    
    /**
    * 将文本信息与异常写入日志文件
    */

    private void log(Throwable e, String msg) {
        ConnectionManager.log(e,msg);
    }
    //设置最后一次访问时间
    private void setLastAccessTime(long ltime){
        ConnectionObject.setLastAccessTime(ltime);
    }

    
}




版权声明   给作者写信
本篇文章对您是否有帮助?  投票:         投票结果:   cool.gif  3     sad.gif  0


  评论人:zhouke    参与分: 228    专家分: 30 发表时间: 2004-6-8 下午12:47
看上去挺好的,最好能提供一个简单的使用实例,还有能不能做成一个多数据库的连接,比如也支持ORCALE,MSSQL等!

  评论人:shegg    参与分: 32    专家分: 100 发表时间: 2004-6-10 下午3:30
其实 还有个文件未贴出来。
db.properties
如下(此文件必须和上述几个类在同一个目录下)

################### db.properties #################################
#dbpool info

#日志文件
logfile=D://Site//Drsl//log.txt

#驱动器(如果有多个以冒号‘:’间隔)
drivers=com.mysql.jdbc.Driver:oracle.jdbc.driver.OracleDriver:net.sourceforge.jtds.jdbc.Driver

#数据库信息块(mysql)
mysql.url=jdbc:mysql://localhost:3306/test

mysql.option=&useUnicode=true&characterEncoding=UTF-8&autoReconnect=false
mysql.user=aaa
mysql.password=bbb
mysql.maxconn=0
mysql.minconn=10
mysql.maxonlinetime=30

#数据库信息块(oracle)
oracle.url=jdbc:oracle:thin:@localhost:1521:ORCL

mysql.option=
mysql.user=aaa
mysql.password=bbb
mysql.maxconn=0
mysql.minconn=10
mysql.maxonlinetime=30

#数据库信息块(ms sql)
oracle.url=jdbc:jtds:sqlserver://127.0.0.1:1433/maste

mysql.option=
mysql.user=aaa
mysql.password=bbb
mysql.maxconn=0
mysql.minconn=10
mysql.maxonlinetime=30

#数据库信息块(....)


#end file

然后修改ConnectionObject.newConnection()为

 private ConnectionObject newConnection() {
        ConnectionObject connobj= null; 
        try {
            log("End One Part/r/n");
            
            log("连接池" + name+"创建一个新的连接对象");
             
            String URL=url+option;             log("URL=" +URL );
             
            Connection conn = DriverManager.getConnection(URL,user,password);            
            connobj=new ConnectionObject(conn,false);
            
            freeConnection(connobj);
            countConn++;
            
        } 
        catch (SQLException e) { 
            log(e, "无法创建下列URL的连接: " + url+" for User= " +user+" Password="+password); 
            return null; 
        } 
        return connobj; 
    } 

同时说明一点,对于PreparedStatement 接口,有的jdbc不支持(如mysql5.0 mysql-jdbc 3.0就会导致异常,程序退出时cpu使用率100%)
因此在使用此连接池时请先阅读相应数据库及其jdbc的使用文档。

  评论人:zhouke    参与分: 228    专家分: 30 发表时间: 2004-6-10 下午5:44
真不错,改天试试,偶用的是MSSQL和ORACLE,所以有上面一问!

  评论人:shegg    参与分: 32    专家分: 100 发表时间: 2004-6-11 上午9:09
失误。。。。
文件db.properties 应如下
如下(此文件必须和上述几个类在同一个目录下)

################### db.properties #################################
#dbpool info

#日志文件
logfile=D://Site//Drsl//log.txt

#驱动器(如果有多个以冒号‘:’间隔)
drivers=com.mysql.jdbc.Driver:oracle.jdbc.driver.OracleDriver:net.sourceforge.jtds.jdbc.Driver

#数据库信息块(mysql)
mysql.url=jdbc:mysql://localhost:3306/test?

mysql.option=&useUnicode=true&characterEncoding=UTF-8&autoReconnect=false
mysql.user=aaa
mysql.password=bbb
mysql.maxconn=0
mysql.minconn=10
mysql.maxonlinetime=30

#数据库信息块(oracle)
oracle.url=jdbc:oracle:thin:@localhost:1521:ORCL

oracle.option=
oracle.user=aaa
oracle.password=bbb
oracle.maxconn=0
oracle.minconn=10
oracle.maxonlinetime=30

#数据库信息块(ms sql)
mssql.url=jdbc:jtds:sqlserver://127.0.0.1:1433/maste

mssql.option=
mssql.user=aaa
mssql.password=bbb
mssql.maxconn=0
mssql.minconn=10
mssql.maxonlinetime=30

#数据库信息块(....)

#end file

  评论人:shegg    参与分: 32    专家分: 100 发表时间: 2004-6-11 下午3:55
更正:
mysql.option=&useUnicode=true&characterEncoding=UTF-8&autoReconnect=false

mysql.option=useUnicode=true&characterEncoding=UTF-8&autoReconnect=false

客人: sinboy 发表时间: 2004-6-11 下午6:13
看着不错,可是就是太长,没有耐心看完。我想对数据库访问接口程序最好的封装只需给客户端提供一个设置DRIVER,URL等参数的方法,另外再给客户端提供一个_ResultSet query(String sql)
,int execute(String sql)的方法就好了,不要客户端关心任何有关建立连接、管理连接的底层操作.这样用起来就最好了

  评论人:shegg    参与分: 32    专家分: 100 发表时间: 2004-6-11 下午10:16
设计该连接池时 主要考虑了以下两点

1。使用时除getConnection()需要用到ConnectionManager 的实例外其他的对象实例(如Connection,ResultSet,PreparedStatement,Statement,etc)都可以直接使用常规的类,主要是因为我接管了这些类的方法。(具体请看我程序里的例子)
2。关于设置Driver,在配置文件里设置。

客人: king 发表时间: 2004-7-8 上午9:06
试了一下,出现如下错误,不止为何?
Source not found for $Proxy1.executeQuery(String) line: not available [local variables unavailable]

自己动手写数据库连接池

在前面的文章中已经说过使用连接池的很多好处和优势,也曾讨论过怎么使用数据库连接池,不过那时用的都是别人写好的一些DataSource类。现在我们自己来写一个数据库连接池,下面使用两种方法来实现,这里分...
  • Senton
  • Senton
  • 2006-10-07 22:28:00
  • 1272

自己动手实现数据库连接池

数据库连接池 1. 数据库连接池是干什么的 假如我们有个应用程序需要每隔10秒查询一次数据库,我们可以用以下方式 方法1:每次查询的时候都新建一个数据库连接,查询结束关闭数据库连接。 ...
  • Deginch
  • Deginch
  • 2017-04-11 17:02:45
  • 1582

自己实现一个数据库连接池

        尽管很多Web服务器厂商已经在服务器内嵌入了数据池的实现,比如Tomcat的DBCP数据库连接池.不过由于其内部的机制开发者并不熟悉.从而出现了Bug不知道该如何去解决.       ...
  • dongfengsun
  • dongfengsun
  • 2006-11-18 18:50:00
  • 3369

实现一个简单的数据库连接池

说明 看到团长公众号的文章,自己参照完成一个简单的数据库连接池 正文 ConnPool 连接池类必须实现javax.sql.DataSource接口 package com.datas...
  • sinat_36553913
  • sinat_36553913
  • 2018-01-06 23:37:27
  • 601

自己动手写个数据库连接池

说到数据库连接池也是初学者会望而却步,认为是如何高深莫测的东西,其实可以用一句话来解释: 连接池的出现是为了用户频繁访问数据库而造成速度和性能上的迟缓才对访问数据库的方法作了一点修改,这个修改就是把原...
  • juejiang
  • juejiang
  • 2007-08-08 22:37:00
  • 1284

Java 的简单数据库连接池实现

一个连接容器,记录连接和连接使用状况package db.khan;import java.sql.*;/**//*数据库连接容器 * */public class DBPoolCon {  /**/...
  • shaopang
  • shaopang
  • 2006-04-09 11:00:00
  • 1015

关于数据库连接池的简单理解

数据库连接池更多的是一个本地的概念。以前一直觉得,数据库连接池是数据库服务器上的一个概念,在数据库服务器上有一个池,里边存放着很多的线程的数据库连接。   最近在分析的时候,发现这是不正确的,或者...
  • sundacheng1989
  • sundacheng1989
  • 2016-10-12 09:46:54
  • 974

ADO.NET 细说数据库连接池

ADO.NET 细说数据库连接池 题外话 通过前几章的学习,不知道大家对ADO.NET有一定的了解了没有。撇开文章质量不讲,必须肯定的是,我是用心去写每一篇文章的。无论是是在排版上,还...
  • moshansk
  • moshansk
  • 2014-08-06 09:58:56
  • 1392

JavaWeb学习笔记之自定义数据库连接池

一、应用程序直接获取数据库连接的缺点  用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极...
  • u014349086
  • u014349086
  • 2016-06-18 11:59:47
  • 1309
收藏助手
不良信息举报
您举报文章:自己写的数据库连接池(二)
举报原因:
原因补充:

(最多只允许输入30个字)