ImageVerifierCode 换一换
格式:DOC , 页数:11 ,大小:85KB ,
资源ID:7019121      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/7019121.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(Java实现数据库连接池.doc)为本站上传会员【xrp****65】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

Java实现数据库连接池.doc

1、使用 JAVA 中的动态代理实现数据库连接池 刘冬,珠海市创我科技发展有限公司软件工程师,主要从事J2EE方面的开发。电子邮件: winter.lau@ 简介: 通过使用 JAVA 中的动态代理实现数据库连接池,使使用者可以以普通的 jdbc 连接的使用习惯来使用连接池。 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈。我们可以在互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共同的问题:这些连接池的实现方法都不同程度地增加了与使用者之间的耦合度。很多的连接池都要求用户通过其规定的方法获取数据库

2、的连接,这一点我们可以理解,毕竟目前所有的应用服务器取数据库连接的方式都是这种方式实现的。但是另外一个共同的问题是,它们同时不允许使用者显式的调用 Connection.close() 方法,而需要用其规定的一个方法来关闭连接。这种做法有两个缺点: 第一:改变了用户使用习惯,增加了用户的使用难度。 首先我们来看看一个正常的数据库操作过程: int executeSQL(String sql) throws SQLException { Connection conn = getConnection(); // 通过某种方式获取数据库连接 PreparedStat

3、ement ps = null; int res = 0; try{ ps = conn.prepareStatement(sql); res = ps.executeUpdate(); }finally{ try{ ps.close(); }catch(Exception e){} try{ conn.close();// }catch(Exception e){} } return res; } 使用者在用完数据库连接后通常是直接调用连接的方法 close 来释放数据库资源,如果用我们

4、前面提到的连接池的实现方法,那语句 conn.close() 将被某些特定的语句所替代。 第二:使连接池无法对之中的所有连接进行独占控制。由于连接池不允许用户直接调用连接的 close 方法,一旦使用者在使用的过程中由于习惯问题直接关闭了数据库连接,那么连接池将无法正常维护所有连接的状态,考虑连接池和应用由不同开发人员实现时这种问题更容易出现。 综合上面提到的两个问题,我们来讨论一下如何解决这两个要命的问题。 首先我们先设身处地的考虑一下用户是想怎么样来使用这个数据库连接池的。用户可以通过特定的方法来获取数据库的连接,同时这个连接的类型应该是标准的 java.sql.Connection

5、用户在获取到这个数据库连接后可以对这个连接进行任意的操作,包括关闭连接等。 通过对用户使用的描述,怎样可以接管 Connection.close 方法就成了我们这篇文章的主题。 为了接管数据库连接的 close 方法,我们应该有一种类似于钩子的机制。例如在 Windows 编程中我们可以利用 Hook API 来实现对某个 Windows API 的接管。在 JAVA 中同样也有这样一个机制。JAVA 提供了一个 Proxy 类和一个 InvocationHandler,这两个类都在 java.lang.reflect 包中。我们先来看看 SUN 公司提供的文档是怎么描述这两个类的。

6、public interface InvocationHandler InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the

7、 invoke method of its invocation handler. SUN 的 API 文档中关于 Proxy 的描述很多,这里就不罗列出来。通过文档对接口 InvocationHandler 的描述我们可以看到当调用一个 Proxy 实例的方法时会触发 Invocationhanlder 的 invoke 方法。从 JAVA 的文档中我们也同时了解到这种动态代理机制只能接管接口的方法,而对一般的类无效,考虑到 java.sql.Connection 本身也是一个接口由此就找到了解决如何接管 close 方法的出路。 首先,我们先定义一个数据库连接池参数的

8、类,定义了数据库的 JDBC 驱动程序类名,连接的 URL 以及用户名口令等等一些信息,该类是用于初始化连接池的参数,具体定义如下: public class ConnectionParam implements Serializable { private String driver; // 数据库驱动程序 private String url; // 数据连接的 URL private String user; // 数据库用户名 private String password; // 数据库密码 pr

9、ivate int minConnection = 0; // 初始化连接数 private int maxConnection = 50; // 最大连接数 private long timeoutValue = 600000;// 连接的最大空闲时间 private long waitTime = 30000; // 取连接的时候如果没有可用连接最大的等待时间 其次是连接池的工厂类 ConnectionFactory,通过该类来将一个连接池对象与一个名称对应起来,使用者通过该名称就可以获取指定的连接池对象,具体代码如下: /** * 连接

10、池类厂,该类常用来保存多个数据源名称合数据库连接池对应的哈希 * @author liusoft */ public class ConnectionFactory { // 该哈希表用来保存数据源名和连接池对象的关系表 static Hashtable connectionPools = null; static{ connectionPools = new Hashtable(2,0.75F); } /** * 从连接池工厂中获取指定名称对应的连接池对象 * @param dataSource 连接池对象

11、对应的名称 * @return DataSource 返回名称对应的连接池对象 * @throws NameNotFoundException 无法找到指定的连接池 */ public static DataSource lookup(String dataSource) throws NameNotFoundException { Object ds = null; ds = connectionPools.get(dataSource); if(ds == null || !(ds instanceof Data

12、Source)) throw new NameNotFoundException(dataSource); return (DataSource)ds; } /** * 将指定的名字和数据库连接配置绑定在一起并初始化数据库连接池 * @param name 对应连接池的名称 * @param param 连接池的配置参数,具体请见类 ConnectionParam * @return DataSource 如果绑定成功后返回连接池对象 * @throws NameAlreadyBoundException 一定名

13、字 name 已经绑定则抛出该异常 * @throws ClassNotFoundException 无法找到连接池的配置中的驱动程序类 * @throws IllegalAccessException 连接池配置中的驱动程序类有误 * @throws InstantiationException 无法实例化驱动程序类 * @throws SQLException 无法正常连接指定的数据库 */ public static DataSource bind(String name, ConnectionParam param)

14、throws NameAlreadyBoundException,ClassNotFoundException, IllegalAccessException,InstantiationException,SQLException { DataSourceImpl source = null; try{ lookup(name); throw new NameAlreadyBoundException(name); }catch(NameNotFoundException e){ source = new

15、DataSourceImpl(param); source.initConnection(); connectionPools.put(name, source); } return source; } /** * 重新绑定数据库连接池 * @param name 对应连接池的名称 * @param param 连接池的配置参数,具体请见类 ConnectionParam * @return DataSource 如果绑定成功后返回连接池对象 * @throws NameAlreadyBoun

16、dException 一定名字 name 已经绑定则抛出该异常 * @throws ClassNotFoundException 无法找到连接池的配置中的驱动程序类 * @throws IllegalAccessException 连接池配置中的驱动程序类有误 * @throws InstantiationException 无法实例化驱动程序类 * @throws SQLException 无法正常连接指定的数据库 */ public static DataSource rebind(String name, ConnectionP

17、aram param) throws NameAlreadyBoundException,ClassNotFoundException, IllegalAccessException,InstantiationException,SQLException { try{ unbind(name); }catch(Exception e){} return bind(name, param); } /** * 删除一个数据库连接池对象 * @param name * @throws Na

18、meNotFoundException */ public static void unbind(String name) throws NameNotFoundException { DataSource dataSource = lookup(name); if(dataSource instanceof DataSourceImpl){ DataSourceImpl dsi = (DataSourceImpl)dataSource; try{ dsi.stop(); dsi.close();

19、 }catch(Exception e){ }finally{ dsi = null; } } connectionPools.remove(name); } } ConnectionFactory 主要提供了用户将将连接池绑定到一个具体的名称上以及取消绑定的操作。使用者只需要关心这两个类即可使用数据库连接池的功能。下面我们给出一段如何使用连接池的代码: String name = "pool"; String driver = " sun.jdbc.odbc.JdbcOdbcDriv

20、er "; String url = "jdbc:odbc:datasource"; ConnectionParam param = new ConnectionParam(driver,url,null,null); param.setMinConnection(1); param.setMaxConnection(5); param.setTimeoutValue(20000); ConnectionFactory.bind(name, param); System.out.println("bind datasource ok.")

21、 // 以上代码是用来登记一个连接池对象,该操作可以在程序初始化只做一次即可 // 以下开始就是使用者真正需要写的代码 DataSource ds = ConnectionFactory.lookup(name); try{ for(int i=0;i<10;i++){ Connection conn = ds.getConnection(); try{ testSQL(conn, sql); }finally{ try{ conn.close(); }catc

22、h(Exception e){} } } }catch(Exception e){ e.printStackTrace(); }finally{ ConnectionFactory.unbind(name); System.out.println("unbind datasource ok."); System.exit(0); } 从使用者的示例代码就可以看出,我们已经解决了常规连接池产生的两个问题。但是我们最最关心的是如何解决接管 close 方法的办法。接管工作主要在 ConnectionFac

23、tory 中的两句代码: source = new DataSourceImpl(param); source.initConnection(); DataSourceImpl 是一个实现了接口 javax.sql.DataSource 的类,该类维护着一个连接池的对象。由于该类是一个受保护的类,因此它暴露给使用者的方法只有接口 DataSource 中定义的方法,其他的所有方法对使用者来说都是不可视的。我们先来关心用户可访问的一个方法 getConnection /** * @see javax.sql.DataSource#getConnection(Stri

24、ng,String) */ public Connection getConnection(String user, String password) throws SQLException { // 首先从连接池中找出空闲的对象 Connection conn = getFreeConnection(0); if(conn == null){ // 判断是否超过最大连接数 , 如果超过最大连接数 // 则等待一定时间查看是否有空闲连接 ,

25、 否则抛出异常告诉用户无可用连接 if(getConnectionCount() >= connParam.getMaxConnection()) conn = getFreeConnection(connParam.getWaitTime()); else{// 没有超过连接数,重新获取一个数据库的连接 connParam.setUser(user); connParam.setPassword(password);

26、 Connection conn2 = DriverManager.getConnection(connParam.getUrl(), user, password); // 代理将要返回的连接对象 _Connection _conn = new _Connection(conn2,true); synchronized(conns){ conns.add(_conn);

27、 } conn = _conn.getConnection(); } } return conn; } /** * 从连接池中取一个空闲的连接 * @param nTimeout 如果该参数值为 0 则没有连接时只是返回一个 null * 否则的话等待 nTimeout 毫秒看是否还有空闲连接,如果没有抛出异常 * @return Connection

28、 * @throws SQLException */ protected synchronized Connection getFreeConnection(long nTimeout) throws SQLException { Connection conn = null; Iterator iter = conns.iterator(); while(iter.hasNext()){ _Connection _conn = (_C

29、onnection)iter.next(); if(!_conn.isInUse()){ conn = _conn.getConnection(); _conn.setInUse(true); break; } } if(conn == null && nTimeout > 0){ // 等待 nTimeout 毫秒以

30、便看是否有空闲连接 try{ Thread.sleep(nTimeout); }catch(Exception e){} conn = getFreeConnection(0); if(conn == null) throw new SQLException("没有可用的数据库连接"); } return conn; } DataSourc

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

32、何实现的,然后再介绍是客户端调用 Connection.close 方法时走的是怎样一个流程,为什么并没有真正的关闭连接。 /** * 数据连接的自封装,屏蔽了 close 方法 * @author Liudong */ class _Connection implements InvocationHandler { private final static String CLOSE_METHOD_NAME = "close"; private Connection conn = null; // 数据库的忙状态

33、 private boolean inUse = false; // 用户最后一次访问该连接方法的时间 private long lastAccessTime = System.currentTimeMillis(); _Connection(Connection conn, boolean inUse){ this.conn = conn; this.inUse = inUse; } /** * Returns the conn. * @

34、return Connection */ public Connection getConnection() { // 返回数据库连接 conn 的接管类,以便截住 close 方法 Connection conn2 = (Connection)Proxy.newProxyInstance( conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),this); retu

35、rn conn2; } /** * 该方法真正的关闭了数据库的连接 * @throws SQLException */ void close() throws SQLException{ // 由于类属性 conn 是没有被接管的连接,因此一旦调用 close 方法后就直接关闭连接 conn.close(); } /** * Returns the inUse. * @return boolean */

36、 public boolean isInUse() { return inUse; } /** * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, * java.lang.reflect.Method, java.lang.Object) */ public Object invoke(Object proxy, Method m, Object[] args) throws

37、 Throwable { Object obj = null; // 判断是否调用了 close 的方法,如果调用 close 方法则把连接置为无用状态 if(CLOSE_METHOD_NAME.equals(m.getName())) setInUse(false); else obj = m.invoke(conn, args); // 设置最后一次访问时间,以便及时清除超时的连接

38、 lastAccessTime = System.currentTimeMillis(); return obj; } /** * Returns the lastAccessTime. * @return long */ public long getLastAccessTime() { return lastAccessTime; } /** * Sets the inUse.

39、 * @param inUse The inUse to set */ public void setInUse(boolean inUse) { this.inUse = inUse; } } 一旦使用者调用所得到连接的 close 方法,由于用户的连接对象是经过接管后的对象,因此 JAVA 虚拟机会首先调用 _Connection.invoke 方法,在该方法中首先判断是否为 close 方法,如果不是则将代码转给真正的没有被接管的连接对象 conn。否则的话只是简单的将该连接的状态设置为可用。到此您可能就明白了

40、整个接管的过程,但是同时也有一个疑问:这样的话是不是这些已建立的连接就始终没有办法真正关闭?答案是可以的。我们来看看 ConnectionFactory.unbind 方法,该方法首先找到名字对应的连接池对象,然后关闭该连接池中的所有连接并删除掉连接池。在 DataSourceImpl 类中定义了一个 close 方法用来关闭所有的连接,详细代码如下: /** * 关闭该连接池中的所有数据库连接 * @return int 返回被关闭连接的个数 * @throws SQLException */ public int close() throws SQ

41、LException { int cc = 0; SQLException excp = null; Iterator iter = conns.iterator(); while(iter.hasNext()){ try{ ((_Connection)iter.next()).close(); cc ++; }catch(Exception e){ if(e instanceof SQLException) excp = (SQLException)e; } } if(excp != null) throw excp; return cc; } 该方法一一调用连接池中每个对象的 close 方法,这个 close 方法对应的是 _Connection 中对 close 的实现,在 _Connection 定义中关闭数据库连接的时候是直接调用没有经过接管的对象的关闭方法,因此该 close 方法真正的释放了数据库资源。 以上文字只是描述了接口方法的接管,具体一个实用的连接池模块还需要对空闲连接的监控并及时释放连接,详细的代码请参照附件。

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服