使用JAVA中的动态代理实现数据库连接池Word文档下载推荐.docx
- 文档编号:20713819
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:27
- 大小:21.95KB
使用JAVA中的动态代理实现数据库连接池Word文档下载推荐.docx
《使用JAVA中的动态代理实现数据库连接池Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《使用JAVA中的动态代理实现数据库连接池Word文档下载推荐.docx(27页珍藏版)》请在冰豆网上搜索。
使用者在用完数据库连结后往常是直接调用连结的方法
close来开释数据库资源,假如用我们前方提到的连结池的实
现方法,那语句conn.close()将被某些特定的语句所代替。
第二:
使连结池没法对之中的全部连结进行独占控制。
因为
连结池不一样意用户直接调用连结的close方法,一旦使用者
在使用的过程中因为习惯问题直接封闭了数据库连结,那么
连结池将没法正常保护全部连结的状态,考虑连结池和应用
由不一样开发人员实现时这类问题更简单出现。
综合上边提到的两个问题,我们来议论一下如何解决这两个
要命的问题。
第一我们先身临其境的考虑一下用户是想怎么样来使用这
个数据库连结池的。
用户能够经过特定的方法来获得数据库
的连结,同时这个连结的种类应当是标准的
java.sql.Connection。
用户在获得到这个数据库连结后能够对
这个连结进行随意的操作,包含封闭连结等。
经过对用户使用的描绘,如何能够接收Connection.close方法
就成了我们这篇文章的主题。
为了接收数据库连结的close方法,我们应当有一种近似于
钩子的体制。
比如在Windows编程中我们能够利用HookAPI
来实现对某个WindowsAPI的接收。
在JAVA中相同也有这
样一个体制。
JAVA供给了一个Proxy类和一个
InvocationHandler,这两个类都在java.lang.reflect包中。
我们
先来看看SUN企业供给的文档是怎么描绘这两个类的。
publicinterfaceInvocationHandlerInvocationHandleristheinterfaceimplementedbytheinvocationhandlerofaproxyinstance.Eachproxyinstancehasanassociatedinvocationhandler.
Whenamethodisinvokedonaproxyinstance,
themethodinvocationisencodedanddispatchedtotheinvokemethodofitsinvocationhandler.
SUN的API文档中对于Proxy的描绘好多,这里就不排列出
来。
经过文档对接口InvocationHandler的描绘我们能够看到
当调用一个Proxy实例的方法时会触发Invocationhanlder的
invoke方法。
从JAVA的文档中我们也同时认识到这类动向
代理体制只好接收接口的方法,而对一般的类无效,考虑到
java.sql.Connection自己也是一个接口由此就找到认识决如
何接收close方法的出路。
第一,我们先定义一个数据库连结池参数的类,定义了数据
库的JDBC驱动程序类名,连结的URL以及用户名口令等等
一些信息,该类是用于初始化连结池的参数,详细定义以下:
publicclassConnectionParamimplementsSerializable
privateStringdriver;
//数据库驱动程序
privateStringurl;
//数据连结的URL
privateStringuser;
//数据库用户名
privateStringpassword;
//数据库密码
privateintminConnection=0;
//初始化连结数
privateintmaxConnection=50;
//最大连结数
privatelongtimeoutValue=600000;
//连结的最大安闲时间
privatelongwaitTime=30000;
//取连结的时候假如没
有可用连结最大的等候时间
其次是连结池的工厂类ConnectionFactory,经过该类来将一
个连结池对象与一个名称对应起来,使用者经过该名称便可
以获得指定的连结池对象,详细代码以下:
/**
*连结池类厂,该类常用来保留多个数据源名称合数据库连结池对应的哈希
*@authorliusoft
*/
publicclassConnectionFactory
//该哈希表用来保留数据源名和连结池对象的关系表
staticHashtableconnectionPools=null;
static{
connectionPools=newHashtable(2,0.75F);
/**
*从连结池工厂中获得指命名称对应的连结池对象
*@paramdataSource连结池对象对应的名称
*@returnDataSource返回名称对应的连结池对象
*@throwsNameNotFoundException没法找到指定的连
接池
publicstaticDataSourcelookup(StringdataSource)
throwsNameNotFoundException
Objectds=null;
ds=connectionPools.get(dataSource);
if(ds==null||!
(dsinstanceofDataSource))
thrownewNameNotFoundException(dataSource);
return(DataSource)ds;
}/**
*将指定的名字和数据库连结配置绑定在一同并初始化数据库连结池
*@paramname对应连结池的名称
*@paramparam连结池的配置参数,详细请见类
ConnectionParam
*@returnDataSource假如绑定成功后返回连结池对象
*@throwsNameAlreadyBoundException一命名字
name已经绑定章抛出该异样
*@throwsClassNotFoundException没法找到连结池
的配置中的驱动程序类
*@throwsIllegalAccessException连结池配置中的
驱动程序类有误
*@throwsInstantiationException没法实例化驱动程
序类
*@throwsSQLException没法正常连结指定
的数据库
publicstaticDataSourcebind(Stringname,ConnectionParamparam)
throws
NameAlreadyBoundException,ClassNotFoundException,
IllegalAccessException,InstantiationException,SQLExceptio
n
DataSourceImplsource=null;
lookup(name);
thrownewNameAlreadyBoundException(name);
}catch(NameNotFoundExceptione){
source=newDataSourceImpl(param);
source.initConnection();
connectionPools.put(name,source);
returnsource;
*从头绑定数据库连结池
*@throwsIllegalAccessException
连结池配置中的
publicstaticDataSourcerebind(Stringname,ConnectionParamparam)
unbind(name);
returnbind(name,param);
*删除一个数据库连结池对象
*@paramname
*@throwsNameNotFoundException
publicstaticvoidunbind(Stringname)throwsNameNotFoundException
DataSourcedataSource=lookup(name);
if(dataSourceinstanceofDataSourceImpl){
DataSourceImpldsi=(DataSourceImpl)dataSource;
try{
dsi.stop();
dsi.close();
}catch(Exceptione){
dsi=null;
connectionPools.remove(name);
ConnectionFactory主要供给了用户将将连结池绑定到一个具
体的名称上以及撤消绑定的操作。
使用者只要要关怀这两个
类即可使用数据库连结池的功能。
下边我们给出一段如何使
用连结池的代码:
Stringname="
pool"
;
Stringdriver="
sun.jdbc.odbc.JdbcOdbcDriver"
Stringurl="
jdbc:
odbc:
datasource"
ConnectionParamparam=new
ConnectionParam(driver,url,null,null);
param.setMinConnection
(1);
param.setMaxConnection(5);
param.setTimeoutValue(20000);
ConnectionFactory.bind(name,param);
System.out.println("
binddatasourceok."
);
//以上代码是用来登记一个连结池对象,该操作能够在程
序初始化只做一次即可
//以下开始就是使用者真实需要写的代码DataSourceds=ConnectionFactory.lookup(name);
for(inti=0;
i<
10;
i++){
Connectionconn=ds.getConnection();
testSQL(conn,sql);
e.printStackTrace();
ConnectionFactory.unbind(name);
System.out.println("
unbinddatasourceok."
System.exit(0);
从使用者的示例代码就能够看出,我们已经解决了惯例连结
池产生的两个问题。
可是我们最最关怀的是如何解决接收
close方法的方法。
接收工作主要在ConnectionFactory中的
两句代码:
source=newDataSourceImpl(param);
DataSourceImpl是一个实现了接口javax.sql.DataSource的类,
该类保护着一个连结池的对象。
因为该类是一个受保护的
类,所以它裸露给使用者的方法只有接口DataSource中定义
的方法,其余的全部方法对使用者来说都是不行视的。
先来关怀用户可接见的一个方法getConnection/**
*@seejavax.sql.DataSource#getConnection(String,String)
publicConnectiongetConnection(Stringuser,String
password)throwsSQLException
//第一从连结池中找出安闲的对象
Connectionconn=getFreeConnection(0);
if(conn==null){
//判断能否超出最大连结数,假如超出最大连结数
//则等候一准时间查察能否有安闲连结,不然抛出异
常告诉用户无可用连结
if(getConnectionCount()>
=
connParam.getMaxConnection())
conn=
getFreeConnection(connParam.getWaitTime());
else{//没有超出连结数,从头获得一个数据库的连
接
connParam.setUser(user);
connParam.setPassword(password);
Connectionconn2=
DriverManager.getConnection(connParam.getUrl(),user,password);
//代理将要返回的连结对象
_Connection_conn=new
_Connection(conn2,true);
synchronized(conns){
conns.add(_conn);
conn=_conn.getConnection();
returnconn;
*从连结池中取一个安闲的连结
*@paramnTimeout假如该参数值为0则没有连结时不过返回一个null
*不然的话等候nTimeout毫秒看能否还有安闲连结,假如没有抛出异样
*@returnConnection
*@throwsSQLException
protectedsynchronizedConnectiongetFreeConnection(longnTimeout)
throwsSQLException
Connectionconn=null;
Iteratoriter=conns.iterator();
while(iter.hasNext()){
_Connection_conn=(_Connection)iter.next();
if(!
_conn.isInUse()){
_conn.setInUse(true);
break;
if(conn==null&
&
nTimeout>
0){
//等候nTimeout毫秒以便看能否有安闲连结
Thread.sleep(nTimeout);
conn=getFreeConnection(0);
if(conn==null)
thrownewSQLException("
没有可用的数据库连
接"
DataSourceImpl类中实现getConnection方法的跟正常的数据
库连结池的逻辑是一致的,第一判断能否有安闲的连结,如
果没有的话判断连结数能否已经超出最大连结数等等的一
些逻辑。
可是有一点不一样的是经过DriverManager获得的数
据库连结其实不是实时返回的,而是经过一个叫_Connection
的类中介一下,而后调用_Connection.getConnection返回的。
假如我们没有经过一其中介也就是JAVA中的Proxy来接收
要返回的接口对象,那么我们就没有方法截住
Connection.close方法。
终于到了核心所在,我们先来看看_Connection是如何实现
的,而后再介绍是客户端调用Connection.close方法时走的是
如何一个流程,为何并无真实的封闭连结。
*数据连结的自封装,障蔽了close方法
*@authorLiudong
class_ConnectionimplementsInvocationHandler
privatefinalstaticStringCLOSE_METHOD_NAME="
close"
privateConnectionconn=null;
//数据库的忙状态
privatebooleaninUse=false;
//用户最后一次接见该连结方法的时间
privatelonglastAccessTime=System.currentTimeMillis();
_Connection(Connectionconn,booleaninUse){this.conn=conn;
this.inUse=inUse;
*Returnstheconn.
publicConnectiongetConnection(){
//返回数据库连结conn的接收类,以便截住close方法
(Connection)Proxy.newProxyInstance(
conn.getClass().getClassLoader(),
conn.getClass().getInterfaces(),this);
returnconn2;
*该方法真实的封闭了数据库的连结
voidclose()throwsSQLException{
//因为类属性conn是没有被接收的连结,所以一旦调
用close方法后就直接封闭连结
*ReturnstheinUse.
*@returnboolean
publicbooleanisInUse(){
returninUse;
*@see
java.lang.reflect.InvocationHandler#invoke(java.lang.Object,java.la
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 JAVA 中的 动态 代理 实现 数据库连接