Java实现数据库连接池._第1页
Java实现数据库连接池._第2页
免费预览已结束,剩余15页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、使用JAVA中的动态代理实现数据库连接池简介:通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池。数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服 务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈。我们可以在互联网 上找到很多关于数据库连接池的源程序,但是都发现这样一个共同的问题:这些连 接池的实现方法都不同程度地增加了与使用者之间的耦合度。很多的连接池都要求 用户通过其规定的方法获取数据库的连接,这一点我们可以理解,毕竟目前所有的 应用服务器取数据库连接的方式都是这种方式实现的。但是另外一个共同的问题 是,它们同

2、时不允许使用者显式的调用Conn ectio n.close(方法,而需要用其规定的一个方法来关闭连接。这种做法有两个缺点: 第一:改变了用户使用习惯,增加了用户的使用难度 首先我们来看看一个正常的数据库操作过程:int executeSQL(Stri ng sql throws SQLExcepti onConn ection conn = getCo nn ectio n(; /通过某种方式获取数据库连接PreparedStateme nt ps = nu II;int res = 0;tryps = conn .prepareStateme nt(sql;res = ps.execute

3、Update(;fin allytryps.close(;catch(Excepti on etry conn. close(;catch(Excepti on e return res;使用者在用完数据库连接后通常是直接调用连接的方法close来释放数据库资源,如果用我们前面提到的连接池的实现方法,那语句conn .close(将被某些特定的语句所替代。第二:使连接池无法对之中的所有连接进行独占控制。由于连接池不允许用户直接 调用连接的close方法,一旦使用者在使用的过程中由于习惯问题直接关闭了数 据库连接,那么连接池将无法正常维护所有连接的状态, 考虑连接池和应用由不同 开发人员实现时这

4、种问题更容易出现。综合上面提到的两个问题,我们来讨论一下如何解决这两个要命的问题。首先我们先设身处地的考虑一下用户是想怎么样来使用这个数据库连接池的。用户 可以通过特定的方法来获取数据库的连接,同时这个连接的类型应该是标准的java.sql.Co nn ection。用户在获取到这个数据库连接后可以对这个连接进行任意的操作,包括关闭连接等。通过对用户使用的描述,怎样可以接管Conn ectio n.close方法就成了我们这篇文章的主题。为了接管数据库连接的close方法,我们应该有一种类似于钩子的机制。例如在Windows编程中我们可以利用Hook API来实现对某个Windows API的

5、接管。在JAVA中同样也有这样一个机制。JAVA提供了一个Proxy类和一个InvocationHandler,这两个类都在java.lang.reflect包中。我们先来看看SUN公司提供的文档是怎么描述这两个类的。public in terface Inv ocati onHan dlerInv ocati onHan dler is the in terface impleme nted by the inv ocatio nhan dler of a proxy in sta nee.Each proxy in sta nee has an associated inv ocati o

6、n han dler.When a method is inv oked on a proxy in sta nee,the method inv ocati on is en coded and dispatched to the inv oke method of its invocationhandler.SUN的API文档中关于Proxy的描述很多,这里就不罗列出来。通过文档对接口InvocationHandler的描述我们可以看到当调用一个Proxy实例的方法时会触发In vocatio nhan Ider的in voke方法。从JAVA的文档中我们也同时了解到这种动态代理机制只能接

7、管接口的方法,而对一般的类无效,考虑到java.sql.Co nn ection本身也是一个接口由此就找到了解决如何接管close方法的出路。首先,我们先定义一个数据库连接池参数的类,定义了数据库的JDBC驱动程序类名,连接的URL以及用户名口令等等一些信息,该类是用于初始化连接池的参 数,具体定义如下:public class Connection Param implements Serializableprivate String driver; /数据库驱动程序private String url; /数据连接的URLprivate String user; /数据库用户名privat

8、e Stri ng password; /数据库密码private int minConn ectio n = 0; /private int maxC onnection = 50; / privatelong timeoutValue = 600000;/private long waitTime = 30000; /待时间初始化连接数最大连接数连接的最大空闲时间取连接的时候如果没有可用连接最大的等其次是连接池的工厂类Conn ecti onF actory,通过该类来将一个连接池对象与一个 名称对应起来,使用者通过该名称就可以获取指定的连接池对象,具体代码如下:/* *连接池类厂,该类常

9、用来保存多个数据源名称合数据库连接池对应的哈希* author liusoft*/ public class ConnectionF actory/该哈希表用来保存数据源名和连接池对象的关系表static Hashtable connection Pools = n ull;staticconn ecti on Pools = new Hashtable(2,0.75F;/*从连接池工厂中获取指定名称对应的连接池对象* param dataSource连接池对象对应的名称* return DataSource返回名称对应的连接池对象* throws NameNotFoundException无

10、法找到指定的连接池*/ public static DataSource lookup(Stri ng dataSource throws NameNotF oun dExcepti onObject ds = n ull;ds = conn ecti on Pools.get(dataSource;if(ds = n ull | !(ds in sta nceof DataSourcethrow new NameNotF oun dExcepti on( dataSource;return (DataSourceds;/*将指定的名字和数据库连接配置绑定在一起并初始化数据库连接池* para

11、m name对应连接池的名称* param param连接池的配置参数,具体请见类Conn ectio nParam* return DataSource如果绑定成功后返回连接池对象* throws NameAlreadyBou ndExceptio n定名字n ame已经绑定则抛出该异常* throws ClassNotFou ndExceptio n无法找到连接池的配置中的驱动程序类* throws III egalAccessExceptio n连接池配置中的驱动程序类有误* throws In sta ntiatio nExceptio n无法实例化驱动程序类* throws SQLE

12、xception无法正常连接指定的数据库*/public static DataSource bin d(Stri ng n ame, Conn ectio nParam paramthrows NameAlreadyBo un dExceptio n,ClassNotF oun dExceptio n,IllegalAccessExceptio n,I nsta ntiatio nExceptio n,SQLExceptio nDataSourcelmpI source = n ull;trylookup( name;throw new NameAlreadyBo un dExcepti o

13、n(n ame;catch(NameNotF oun dExceptio n esource = new DataSourceImpl(param;source.i nitC onnection(;conn ectio nPools.put( name, source; retur n source;*重新绑定数据库连接池* param name对应连接池的名称* param param连接池的配置参数,具体请见类Conn ectio nParam* return DataSource如果绑定成功后返回连接池对象* throws NameAlreadyBou ndExceptio n定名字n

14、ame已经绑定则抛出该异常* throws ClassNotFou ndExceptio n无法找到连接池的配置中的驱动程序类* throws III egalAccessExceptio n连接池配置中的驱动程序类有误* throws In sta ntiatio nExceptio n无法实例化驱动程序类* throws SQLException无法正常连接指定的数据库*/ public static DataSource reb in d(Stri ng n ame, Conn ectio nParam param throwsNameAlreadyBo un dExceptio n,C

15、lassNotFo un dExceptio n, lllegalAccessExceptio n,Insta ntiatio nExceptio n,SQLExceptio n tryunbind(n ame;catch(Excepti on e return bind(n ame, param;*删除一个数据库连接池对象* param n ame* throws NameNotF oun dExcepti on*/ public static void unbin d(Stri ng n ame throws NameNotF oun dExcepti on DataSource data

16、Source = lookup( name;if(dataSource in sta nceof DataSourcelmplDataSourceImpl dsi = (DataSourceImpldataSource;trydsi.stop(;dsi.close(;catch(Excepti on e fin allydsi = n ull; conn ecti on Pools.remove( name;Conn ecti onF actory主要提供了用户将将连接池绑定到一个具体的名称上以及取消 绑定的操作。使用者只需要关心这两个类即可使用数据库连接池的功能。下面我们 给出一段如何使用连

17、接池的代码:Stri ng n ame = pool;String driver = sun .jdbc.odbc.JdbcOdbcDriver ;String url = jdbc:odbc:datasource;Conn ectio nParam param = new Connection Param(driver,url, null ,nu II;param.setMi nConn ectio n(1;param.setMaxC onn ecti on(5;param.setTimeoutValue(20000;Conn ectio nF actory.bi nd( name, par

18、am;System.out.pri ntln (b ind datasource ok.;/以上代码是用来登记一个连接池对象,该操作可以在程序初始化只做一次即可/以下开始就是使用者真正需要写的代码DataSource ds = ConnectionF actory .lo okup( name;tryfor(int i=0;i= conn Param.getMaxC onnection(conn = getFreeC onnection(conn Param.getWaitTime(;else/没有超过连接数,重新获取一个数据库的连接conn Param.setUser(user;conn P

19、aram.setPassword(password;Conn ecti on conn2 = DriverMa nager.getC onn ecti on(conn Param.getUrl(, user,password;/代理将要返回的连接对象Connection _conn = new _Conn ectio n(c onn 2,true;synchroni zed(c onns conn s.add(_c onn;conn = _conn. getC onnection(;retur n conn;/* *从连接池中取一个空闲的连接* param nTimeout如果该参数值为0则没

20、有连接时只是返回一个null*否则的话等待nTimeout毫秒看是否还有空闲连接,如果没有抛出异常* retur n Conn ecti on* throws SQLExcepti on*/ protected synchroni zed Conn ecti on getFreeC onnection (I ong n Timeout throwsSQLExcepti on Conn ecti on conn = n ull;Iterator iter = conn s.iterator(;while(iter.hasNext( Connection _conn = (_Conn ectio

21、niter. next(;if(!_conn .isl nUse( conn = _conn. getC onnection(;_conn. set In Use(true;break;if(conn = n ull & n Timeout 0/等待nTimeout毫秒以便看是否有空闲连接tryThread.sleep( nTimeout;catch(Excepti on econn = getFreeC onnection(0;if(conn = n ullthrow new SQLException(”没有可用的数据库连接retur n conn;DataSourcelmpI类中实

22、现getConnection方法的跟正常的数据库连接池的逻辑是 一致的,首先判断是否有空闲的连接,如果没有的话判断连接数是否已经超过最大 连接数等等的一些逻辑。但是有一点不同的是通过DriverMa nager得到的数据库连接并不是及时返回的,而是通过一个叫_Conn ection的类中介一下,然后调用_Connection.getConnection返回的。如果我们没有通过一个中介也就是JAVA中的Proxy来接管要返回的接口对象,那么我们就没有办法截住Connection.close方法。终于到了核心所在,我们先来看看_Conn ecti on是如何实现的,然后再介绍是客 户端调用Conn

23、ection.close方法时走的是怎样一个流程,为什么并没有真正的关 闭连接。/* *数据连接的自圭寸装,屏蔽了close方法* author Liudo ng*/ class Connection impleme nts Inv ocati onHan dler private fi nal static Stri ngCLOSE_METHOD_NAME = close;private Conn ecti on conn = n ull;/数据库的忙状态private boolean in Use = false;/用户最后一次访问该连接方法的时间private long lastAcce

24、ssTime = System.currentTimeMillis(;_Conn ectio n(C onn ectio n conn, boolea n in Usethis.c onn = conn;this.i nUse = in Use;Retur ns the conn.return Conn ecti on */public Connection getCo nn ecti on( II返回数据库连接conn的接管类,以便截住close方法Conn ecti on conn2 = (Conn ecti on Proxy .n ewProxy In sta nce( conn.get

25、Class(.getClassLoader(, conn. getClass(.get In terfaces(,this; retur n conn2;/*该方法真正的关闭了数据库的连接* throws SQLExcepti on*/void close( throws SQLExcepti on/由于类属性conn是没有被接管的连接,因此一旦调用close关闭连接conn. close(;Returns the in Use.* retur n boolea n*/ public boolea n isln Use( return in Use;方法后就直接/* see java.la n

26、g.reflect .Invo cati onHan dler#i nv oke(javaa ng.Object,* java.la ng.reflect.Method, java.la ng.Object*/public Object inv oke(Object proxy, Method m, Object args throws ThrowableObject obj = n ull;II判断是否调用了close的方法,如果调用close方法则把连接置为无用状态if(CLOSE_METHOD_NAME.equals(m.getName(setl nUse(false;else obj = m.i nv oke(c onn, args;II设置最后一次访问时间,以便及时清除超时的连接lastAccessTime = System.curre ntTimeMillis(;return obj;* Returns the lastAccessTime.* return long*Ipublic long getLastAccessTime( return lastAccessTime;* Sets the in Use.* param in Use The in Use to set*/public void set In Use(boolea

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论