⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 使用java中的动态代理实现数据库连接池.htm

📁 使用JAVA中的动态代理实现数据库连接池
💻 HTM
📖 第 1 页 / 共 3 页
字号:
                        conn;<BR>&nbsp;}<BR>&nbsp;/**<BR>&nbsp; * 
                        从连接池中取一个空闲的连接<BR>&nbsp; * @param 
                        nTimeout&nbsp;如果该参数值为0则没有连接时只是返回一个null<BR>&nbsp; * 
                        否则的话等待nTimeout毫秒看是否还有空闲连接,如果没有抛出异常<BR>&nbsp; * @return 
                        Connection<BR>&nbsp; * @throws SQLException<BR>&nbsp; 
                        */<BR>&nbsp;protected synchronized Connection 
                        getFreeConnection(long nTimeout) <BR>&nbsp;&nbsp;throws 
                        SQLException<BR>&nbsp;{<BR>&nbsp;&nbsp;Connection conn = 
                        null;<BR>&nbsp;&nbsp;Iterator iter = 
                        conns.iterator();<BR>&nbsp;&nbsp;while(iter.hasNext()){<BR>&nbsp;&nbsp;&nbsp;_Connection 
                        _conn = 
                        (_Connection)iter.next();<BR>&nbsp;&nbsp;&nbsp;if(!_conn.isInUse()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;conn 
                        = 
                        _conn.getConnection();<BR>&nbsp;&nbsp;&nbsp;&nbsp;_conn.setInUse(true);&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;break;<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;if(conn 
                        == null &amp;&amp; nTimeout &gt; 
                        0){<BR>&nbsp;&nbsp;&nbsp;//等待nTimeout毫秒以便看是否有空闲连接<BR>&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(nTimeout);<BR>&nbsp;&nbsp;&nbsp;}catch(Exception 
                        e){}<BR>&nbsp;&nbsp;&nbsp;conn = 
                        getFreeConnection(0);<BR>&nbsp;&nbsp;&nbsp;if(conn == 
                        null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;throw new 
                        SQLException("没有可用的数据库连接");<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;return 
                        conn;<BR>&nbsp;}</P>
                        <P>  DataSourceImpl类中实现getConnection方法的跟正常的数据库连接池的逻辑是一致的,首先判断是否有空闲的连接,如果没有的话判断连接数是否已经超过最大连接数等等的一些逻辑。但是有一点不同的是通过DriverManager得到的数据库连接并不是及时返回的,而是通过一个叫_Connection的类中介一下,然后调用_Connection.getConnection返回的。如果我们没有通过一个中介也就是JAVA中的Proxy来接管要返回的接口对象,那么我们就没有办法截住Connection.close方法。</P>
                        <P>  终于到了核心所在,我们先来看看_Connection是如何实现的,然后再介绍是客户端调用Connection.close方法时走的是怎样一个流程,为什么并没有真正的关闭连接。</P>
                        <P style="BACKGROUND: #eeeeee">/**<BR>&nbsp;* 
                        数据连接的自封装,屏蔽了close方法<BR>&nbsp;* @author 
                        Liudong<BR>&nbsp;*/<BR>class _Connection implements 
                        InvocationHandler<BR>{<BR>&nbsp;private final static 
                        String CLOSE_METHOD_NAME = "close";<BR>&nbsp;private 
                        Connection conn = 
                        null;<BR>&nbsp;//数据库的忙状态<BR>&nbsp;private boolean inUse 
                        = false;<BR>&nbsp;//用户最后一次访问该连接方法的时间<BR>&nbsp;private 
                        long lastAccessTime = 
                        System.currentTimeMillis();<BR>&nbsp;<BR>&nbsp;_Connection(Connection 
                        conn, boolean inUse){<BR>&nbsp;&nbsp;this.conn = 
                        conn;<BR>&nbsp;&nbsp;this.inUse = 
                        inUse;<BR>&nbsp;}<BR>&nbsp;/**<BR>&nbsp; * Returns the 
                        conn.<BR>&nbsp; * @return Connection<BR>&nbsp; 
                        */<BR>&nbsp;public Connection getConnection() 
                        {<BR>&nbsp;&nbsp;//返回数据库连接conn的接管类,以便截住close方法<BR>&nbsp;&nbsp;Connection 
                        conn2 = 
                        (Connection)Proxy.newProxyInstance(<BR>&nbsp;&nbsp;&nbsp;conn.getClass().getClassLoader(),<BR>&nbsp;&nbsp;&nbsp;conn.getClass().getInterfaces(),this);<BR>&nbsp;&nbsp;return 
                        conn2;<BR>&nbsp;}<BR>&nbsp;/**<BR>&nbsp; * 
                        该方法真正的关闭了数据库的连接<BR>&nbsp; * @throws 
                        SQLException<BR>&nbsp; */<BR>&nbsp;void close() throws 
                        SQLException{<BR>&nbsp;&nbsp;//由于类属性conn是没有被接管的连接,因此一旦调用close方法后就直接关闭连接<BR>&nbsp;&nbsp;conn.close();<BR>&nbsp;}<BR>&nbsp;/**<BR>&nbsp; 
                        * Returns the inUse.<BR>&nbsp; * @return 
                        boolean<BR>&nbsp; */<BR>&nbsp;public boolean isInUse() 
                        {<BR>&nbsp;&nbsp;return 
                        inUse;<BR>&nbsp;}<BR><BR>&nbsp;/**<BR>&nbsp; * @see 
                        java.lang.reflect.InvocationHandler#invoke(java.lang.Object, 
                        java.lang.reflect.Method, java.lang.Object)<BR>&nbsp; 
                        */<BR>&nbsp;public Object invoke(Object proxy, Method m, 
                        Object[] args) <BR>&nbsp;&nbsp;throws Throwable 
                        <BR>&nbsp;{<BR>&nbsp;&nbsp;Object obj = 
                        null;<BR>&nbsp;&nbsp;//判断是否调用了close的方法,如果调用close方法则把连接置为无用状态<BR>&nbsp;&nbsp;if(CLOSE_METHOD_NAME.equals(m.getName()))<BR>&nbsp;&nbsp;&nbsp;setInUse(false);&nbsp;&nbsp;<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;obj 
                        = m.invoke(conn, 
                        args);&nbsp;<BR>&nbsp;&nbsp;//设置最后一次访问时间,以便及时清除超时的连接<BR>&nbsp;&nbsp;lastAccessTime 
                        = System.currentTimeMillis();<BR>&nbsp;&nbsp;return 
                        obj;<BR>&nbsp;}<BR>&nbsp;&nbsp;<BR>&nbsp;/**<BR>&nbsp; * 
                        Returns the lastAccessTime.<BR>&nbsp; * @return 
                        long<BR>&nbsp; */<BR>&nbsp;public long 
                        getLastAccessTime() {<BR>&nbsp;&nbsp;return 
                        lastAccessTime;<BR>&nbsp;}<BR><BR>&nbsp;/**<BR>&nbsp; * 
                        Sets the inUse.<BR>&nbsp; * @param inUse The inUse to 
                        set<BR>&nbsp; */<BR>&nbsp;public void setInUse(boolean 
                        inUse) {<BR>&nbsp;&nbsp;this.inUse = 
                        inUse;<BR>&nbsp;}<BR>}</P>
                        <P>  一旦使用者调用所得到连接的close方法,由于用户的连接对象是经过接管后的对象,因此JAVA虚拟机会首先调用_Connection.invoke方法,在该方法中首先判断是否为close方法,如果不是则将代码转给真正的没有被接管的连接对象conn。否则的话只是简单的将该连接的状态设置为可用。到此您可能就明白了整个接管的过程,但是同时也有一个疑问:这样的话是不是这些已建立的连接就始终没有办法真正关闭?答案是可以的。我们来看看ConnectionFactory.unbind方法,该方法首先找到名字对应的连接池对象,然后关闭该连接池中的所有连接并删除掉连接池。在DataSourceImpl类中定义了一个close方法用来关闭所有的连接,详细代码如下:</P>
                        <P style="BACKGROUND: #eeeeee">&nbsp;/**<BR>&nbsp; * 
                        关闭该连接池中的所有数据库连接<BR>&nbsp; * @return int 
                        返回被关闭连接的个数<BR>&nbsp; * @throws SQLException<BR>&nbsp; 
                        */<BR>&nbsp;public int close() throws 
                        SQLException<BR>&nbsp;{<BR>&nbsp;&nbsp;int cc = 
                        0;<BR>&nbsp;&nbsp;SQLException excp = 
                        null;<BR>&nbsp;&nbsp;Iterator iter = 
                        conns.iterator();<BR>&nbsp;&nbsp;while(iter.hasNext()){<BR>&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;((_Connection)iter.next()).close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;cc 
                        ++;<BR>&nbsp;&nbsp;&nbsp;}catch(Exception 
                        e){<BR>&nbsp;&nbsp;&nbsp;&nbsp;if(e instanceof 
                        SQLException)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;excp = 
                        (SQLException)e;<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;if(excp 
                        != null)<BR>&nbsp;&nbsp;&nbsp;throw 
                        excp;<BR>&nbsp;&nbsp;return cc;<BR>&nbsp;}</P>
                        <P>  该方法一一调用连接池中每个对象的close方法,这个close方法对应的是_Connection中对close的实现,在_Connection定义中关闭数据库连接的时候是直接调用没有经过接管的对象的关闭方法,因此该close方法真正的释放了数据库资源。</P>
                        <P>  以上文字只是描述了接口方法的接管,具体一个实用的连接池模块还需要对空闲连接的监控并及时释放连接。</P></TD></TR></TBODY></TABLE></TD></TR>
              <TR>
                <TD width=10 height=11><IMG height=11 
                  src="使用JAVA中的动态代理实现数据库连接池.files/u_16.gif" width=10></TD>
                <TD style="BORDER-BOTTOM: #e8e8e8 1px solid" width=695 
                bgColor=#f9f9f9 height=11><IMG height=1 src="" width=1></TD>
                <TD width=10 height=11><IMG height=11 
                  src="使用JAVA中的动态代理实现数据库连接池.files/u_17.gif" 
              width=10></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
      <DIV align=right>页面功能&nbsp; 【<A 
      href="javascript:window.external.AddFavorite(location.href,document.title+'--www.JavaFan.NET');">加入收藏</A>】 
      【<A 
      onclick="window.open(this.href,'','top=180,left=240,width=342,height=326,scrollbars=yes,resizable=no');return false;" 
      href="http://www.javafan.net/sendarticle.jsp?title=使用JAVA中的动态代理实现数据库连接池&amp;URL=20050124143602938">推荐给朋友</A>】 
      【字体:<A class=black href="javascript:fontZoom(15)">大</A>&nbsp;<A 
      class=black href="javascript:fontZoom(13)">中</A>&nbsp;<A class=black 
      href="javascript:fontZoom(12)">小</A>】 【<A class=black 
      href="javascript:window.close()">关闭</A>】&nbsp;&nbsp;&nbsp; </DIV></TD></TR>
  <TR>
    <TD vAlign=top><IMG height=12 src="使用JAVA中的动态代理实现数据库连接池.files/u_06.gif" 
      width=751></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width=750 align=center border=0>
  <TBODY>
  <TR>
    <TD bgColor=#cacaca height=1></TD></TR>
  <TR>
    <TD vAlign=center align=middle height=30>Copyright &copy; 2003 - 2005 
      JavaFan.NET All Rights Reserved</TD></TR></TBODY></TABLE></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -