现在的位置: 首页 > 综合 > 正文

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

2013年08月12日 ⁄ 综合 ⁄ 共 17909字 ⁄ 字号 评论关闭


**
 * 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);
    }

    
}

版权声明   给作者写信
本篇文章对您是否有帮助?  投票:         投票结果:     3       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]

抱歉!评论已关闭.