﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Energy of Love-随笔分类-Spring</title><link>http://www.blogjava.net/titanaly/category/39909.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 28 Jul 2010 08:23:55 GMT</lastBuildDate><pubDate>Wed, 28 Jul 2010 08:23:55 GMT</pubDate><ttl>60</ttl><item><title>可用Jamon来监测你的Spring应用,sql执行效率(转)</title><link>http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 28 Jul 2010 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/327330.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/327330.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/327330.html</trackback:ping><description><![CDATA[/** <br />
*作者：张荣华(ahuaxuan) <br />
*2007-8-15 <br />
*转载请注明出处及作者 <br />
*/ <br />
<br />
前两天在看Spring内置的拦截器的时候，发现了一个之前没有注意的类：org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor，好奇心促使我上网查了一下这个jamon。大概看了一下之后发现这个玩意还真挺好用的而且挺重要的，而且现在国内对它的介绍也很少，所以写了一篇文章和大家分享。 <br />
<br />
一，Jamon简介： <br />
Jamon的全名是：Java Application Monitor。它是一个小巧的，免费的，高性能的，线程安全的性能监测工具。它可以用来测定系统的性能瓶颈，也可以用来监视用户和应用程序之间的交互情况。 Jamon主要是用来检测jee的应用程序。它最新的版本是2.1，可以用在1.4以上的jdk上。 <br />
<br />
二，将jamon导入到你的应用程序中去 <br />
首先下载jamon的开发包，见我的附件，同时你也可以去Sourceforge上自己下载。Sourceforge的下载地址为http://jamonapi.sourceforge.net。解压之后可以得到一个jar包和一个war包。jar包是自己会用到的，而war包是一个例子（不要小看这个例子，待会也要把它导入到项目中）。把war包之间丢到服务器上，访问：localhost:8080/jamon就可以看到这个例子了，这个例子是一个简单的性能监控系统。 <br />
<br />
接着把例子中的所有的包都导入到项目中，并把war包中的jsp和images还有css都考到项目中，比如新建一个目录叫monitor（它和WEB-INF是同级目录）。 <br />
<br />
三，正确配置自己的应用 <br />
我们在性能监测的时候最监测的就是页面的访问率和类中方法的访问率。所以在这一部分主要讲解一下如何监测自己的页面和类中方法的访问。 <br />
<br />
1， 检测自己的页面访问率 <br />
首先我们需要在web.xml中添加一个filter，这个filter就是用来判断哪些页面需要被监视的，如下所示： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;filter&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-</span><span class="keyword">class</span><span>&gt;com.easywebwork.filter.EasyPageMonFilter&lt;/filter-</span><span class="keyword">class</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/filter&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-mapping&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/filter-mapping&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;filter&gt;
&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt;
&lt;filter-class&gt;com.easywebwork.filter.EasyPageMonFilter&lt;/filter-class&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
</pre>
接下来我们看看这个filter的写法： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;张荣华（ahuaxuan） </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@since&nbsp;2007-8-13 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PageMonFilter&nbsp;</span><span class="keyword">extends</span><span>&nbsp;JAMonFilter{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">final</span><span>&nbsp;</span><span class="keyword">long</span><span>&nbsp;serialVersionUID&nbsp;=&nbsp;5746197114960908454L; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;doFilter(ServletRequest&nbsp;request,&nbsp;ServletResponse&nbsp;response,&nbsp;FilterChain&nbsp;filterChain)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;IOException,&nbsp;ServletException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Monitor&nbsp;allPages&nbsp;=&nbsp;MonitorFactory.start(</span><span class="keyword">new</span><span>&nbsp;MonKeyImp(</span><span class="string">"org.easywebwork.allPages"</span><span>,getURI(request),</span><span class="string">"ms."</span><span>)); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//这里就是我们要监视的所有的页面的配置 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Monitor&nbsp;monitor&nbsp;=&nbsp;MonitorFactory.start(getURI(request)); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//这里就是我们要监视的某个页面的配置 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filterChain.doFilter(request,&nbsp;response); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">finally</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;monitor.stop(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allPages.stop(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span>&nbsp;String&nbsp;getURI(ServletRequest&nbsp;request)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(request&nbsp;</span><span class="keyword">instanceof</span><span>&nbsp;HttpServletRequest)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;((HttpServletRequest)&nbsp;request).getRequestURI(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span><span class="keyword">else</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="string">"Not&nbsp;an&nbsp;HttpServletRequest"</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;FilterConfig&nbsp;filterConfig&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* @author 张荣华（ahuaxuan）
*
* @since 2007-8-13
*/
public class PageMonFilter extends JAMonFilter{
private static final long serialVersionUID = 5746197114960908454L;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
Monitor allPages = MonitorFactory.start(new MonKeyImp("org.easywebwork.allPages",getURI(request),"ms."));
//这里就是我们要监视的所有的页面的配置
Monitor monitor = MonitorFactory.start(getURI(request));
//这里就是我们要监视的某个页面的配置
try {
filterChain.doFilter(request, response);
} finally {
monitor.stop();
allPages.stop();
}
}
protected String getURI(ServletRequest request) {
if (request instanceof HttpServletRequest) {
return ((HttpServletRequest) request).getRequestURI();
} 	else {
return "Not an HttpServletRequest";
}
}
private FilterConfig filterConfig = null;
}}
</pre>
<br />
这个类看上去很简单，其实也挺简单的，就是得到uri，然后把它注册到MonitorFactory类中。这样只要我们去访问刚才创建的monitor目录下的jsp就可以看到性能监测页面了。 <br />
<br />
2， ，接下来我们看看在使用spring的情况下如何监测一个bean的方法调用。Spring也提供了对Jamon的支持(spring支持的东西还真多啊)，也就是文章开头提出的那个拦截器，为了给我们的bean加上拦截器，我们在spring的applicationcontext配置文件中加入如下语句： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;bean&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"beanNames"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;userService&lt;/value&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"interceptorNames"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;jamonInterceptor&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean&nbsp;id=</span><span class="string">"jamonInterceptor"</span><span>&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&lt;/bean&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;
&lt;property name="beanNames"&gt;
&lt;list&gt;
&lt;value&gt;userService&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="interceptorNames"&gt;
&lt;list&gt;
&lt;value&gt;jamonInterceptor&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="jamonInterceptor" class="org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"&gt;
&lt;/bean&gt;</pre>
<br />
上面这个是典型的spring的aop的配置，如果对spring的aop配置不了解的可以去看一下spring中文文档，当然如果不想了解的话即使直接把这段配置拷到自己的项目中也是可以直接使用的。 <br />
<br />
还有一个步骤就是在你的log4j.properties中加入这句代码： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>log4j.logger.org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor&nbsp;=&nbsp;TRACE&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">log4j.logger.org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor = TRACE</pre>
<br />
如果没有这一行，那么这个拦截器是不会把方法调用的信息向MonitorFactory注册的。 <br />
<br />
只需要这些步骤，userservice中的方法在调用的时候就可以被拦截，然后将其注册到MonitorFactory中去了。 <br />
<br />
所有的配置完成之后我们来看一下效果吧: <br />
<a href="http://www.javaeye.com/topics/download/b2bac96e-6c18-4340-b7e0-f84c7bb6adca" target="_blank">http://www.javaeye.com/topics/download/b2bac96e-6c18-4340-b7e0-f84c7bb6adca</a>从这个图上我们可以看到，所有页面被访问的次数，UserService中的getAllUsers被调用的次数，最右边的是访问时间。这只是整个图的一部分，当然这个页面中也包括每一个页面被访问的次数和第一次访问的时间等等。下载附件运行，就可以看到所有的页面了。 <br />
<br />
三，总结 <br />
根据以上的步骤，我们就可以监测我们的程序了，应用程序中哪些页面被访问的多，哪些页面被访问的少，哪些方法被访问的多，哪些方法被访问的少，以及访问高峰期集中在什么时间等等，有了这些参数，我们更可以有针对性的对应用程序进行优化了，比如说某个页面访问比较频繁，我就可以用ehcache或oscache给这个页面做一个缓存。如果某个方法的访问比较频繁那就看看这个方法能否进一步优化，是需要异步，还是需要缓存，还是需要其他等等，总之有了jamon可以给我们带来更多的便捷，既可以让我们知道我们的客户的行为，也可以让我们知道我们开发的程序的&#8220;能力&#8221;。 <br />
<br />
其实本文提供的只是对页面和方法调用的监控，但是jamon可以提供更多功能，比如说sql语句的监控等等，这就需要我们共同去发掘了。 <br />
<br />
附件中包括了一个easywebwork的例子，我把jamon导入到这个例子工程中去，大家可以直接下载运行观看效果。Easywebwork是一个旨在减少webwork2.2.x系列的xml配置文件的项目， <br />
如果对这个主题感兴趣请到 <br />
<a href="http://www.javaeye.com/topic/91614" target="_blank">http://www.javaeye.com/topic/91614</a> <br />
<a href="http://www.javaeye.com/topic/93814" target="_blank">http://www.javaeye.com/topic/93814</a> <br />
参加讨论。 <br />
<br />
<br />
<br />
<br />
<br />
之前有一篇文章讲到如何使用jamon来监控请求以及方法得调用(原文地址见：[url]http://www.javaeye.com/post/354575 [/url])，本文属于其姊妹篇，使用jamon监控系统的sql调用及其调用效率。 <br />
<br />
需求： <br />
1我们知道在使用hibernate得时候，我们可以打开show sql选项，可以直接查看sql语句调用的情况，那么当我们使用其他持久技术的时候我们也需要这个功能怎么办呢，没有关系，jamon能够帮我们做到。 <br />
<br />
2 很多时候，不同的程序员会写出不同的性能的sql，有时候可能会不小心或者因为不知道而写出性能很差的sql，我自己曾经就发生过这种事情，在500w条数据的表里使用了一个limit来分页，到后面，执行一条sql都需要几分钟，诸如此类的时候可能大家都有碰到过，如果能有监控sql性能的工具嵌在应用里该多好，当然有jamon就可以帮我们做到。 <br />
<br />
对于jamon来说，每一个query的执行之后的统计结果都会被保存下来，这些概要统计都以MonProxy-SQL开头。这些统计中包括查询执行的时间，有比如平均时间，执行总时间，最小执行时间，最大执行时间，这些东西难道不是我们正想要的吗。 <br />
<br />
那么让我们开始吧，我们知道，这些query执行的统计应该是在connection中被统计的，也就是说我们要代理一般的connection，而connection又是由datasource产生的，所以我们可以代理datasource，说干就干。 <br />
<br />
一个datasource接口中关于connection的方法只有两个： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;Attempts&nbsp;to&nbsp;establish&nbsp;a&nbsp;connection&nbsp;with&nbsp;the&nbsp;data&nbsp;source&nbsp;that </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;this&nbsp;&lt;code&gt;DataSource&lt;/code&gt;&nbsp;object&nbsp;represents. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;&nbsp;a&nbsp;connection&nbsp;to&nbsp;the&nbsp;data&nbsp;source </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@exception&nbsp;SQLException&nbsp;if&nbsp;a&nbsp;database&nbsp;access&nbsp;error&nbsp;occurs </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Connection&nbsp;getConnection()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;Attempts&nbsp;to&nbsp;establish&nbsp;a&nbsp;connection&nbsp;with&nbsp;the&nbsp;data&nbsp;source&nbsp;that </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;this&nbsp;&lt;code&gt;DataSource&lt;/code&gt;&nbsp;object&nbsp;represents. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;username&nbsp;the&nbsp;database&nbsp;user&nbsp;on&nbsp;whose&nbsp;behalf&nbsp;the&nbsp;connection&nbsp;is&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;being&nbsp;made </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;password&nbsp;the&nbsp;user's&nbsp;password </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;&nbsp;a&nbsp;connection&nbsp;to&nbsp;the&nbsp;data&nbsp;source </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@exception&nbsp;SQLException&nbsp;if&nbsp;a&nbsp;database&nbsp;access&nbsp;error&nbsp;occurs </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@since&nbsp;1.4 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Connection&nbsp;getConnection(String&nbsp;username,&nbsp;String&nbsp;password)&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* &lt;p&gt;Attempts to establish a connection with the data source that
* this &lt;code&gt;DataSource&lt;/code&gt; object represents.
*
* @return  a connection to the data source
* @exception SQLException if a database access error occurs
*/
Connection getConnection() throws SQLException;
/**
* &lt;p&gt;Attempts to establish a connection with the data source that
* this &lt;code&gt;DataSource&lt;/code&gt; object represents.
*
* @param username the database user on whose behalf the connection is
*  being made
* @param password the user's password
* @return  a connection to the data source
* @exception SQLException if a database access error occurs
* @since 1.4
*/
Connection getConnection(String username, String password)
throws SQLException;
</pre>
<br />
也就是说我们只要override这两个方法即可。 <br />
根据这个思路我写了以下代码： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;ahuaxuan(aaron&nbsp;zhang) </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@since&nbsp;2008-2-25 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@version&nbsp;$Id$ </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MonitorDataSource&nbsp;</span><span class="keyword">implements</span><span>&nbsp;DataSource&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;DataSource&nbsp;realDataSource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setRealDataSource(DataSource&nbsp;realDataSource)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.realDataSource&nbsp;=&nbsp;realDataSource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;DataSource&nbsp;getRealDataSource()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;realDataSource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Connection&nbsp;getConnection()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span class="comment">//表示由jamon来代理realDataSource返回的Connection </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;MonProxyFactory.monitor(realDataSource.getConnection()); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Connection&nbsp;getConnection(String&nbsp;username,&nbsp;String&nbsp;password) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span class="comment">//表示由jamon来代理realDataSource返回的Connection </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;MonProxyFactory.monitor(realDataSource.getConnection(username, &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password)); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* @author ahuaxuan(aaron zhang)
* @since 2008-2-25
* @version $Id$
*/
public class MonitorDataSource implements DataSource {
public DataSource realDataSource;
public void setRealDataSource(DataSource realDataSource) {
this.realDataSource = realDataSource;
}
public DataSource getRealDataSource() {
return realDataSource;
}
public Connection getConnection() throws SQLException {
//表示由jamon来代理realDataSource返回的Connection
return MonProxyFactory.monitor(realDataSource.getConnection());
}
public Connection getConnection(String username, String password)
throws SQLException {
//表示由jamon来代理realDataSource返回的Connection
return MonProxyFactory.monitor(realDataSource.getConnection(username,
password));
}
}
</pre>
<br />
显然这个一个代理模式。接下来就是生成这个代理类,我是在spring中注册了这么一个类： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;bean&nbsp;id=</span><span class="string">"writeMonitorDataSource"</span><span>&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.ahuaxuan.MonitorDataSource"</span><span>&nbsp;destroy-method=</span><span class="string">"close"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"realDataSource"</span><span>&nbsp;ref=</span><span class="string">"writeDataSource"</span><span>/&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;bean id="writeMonitorDataSource" class="org.ahuaxuan.MonitorDataSource" destroy-method="close"&gt;
&lt;property name="realDataSource" ref="writeDataSource"/&gt;
&lt;/bean&gt;</pre>
<br />
<br />
writeMonitorDataSource 所依赖的writeDataSource就是我们真正配置的datasource，比如： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;bean&nbsp;id=</span><span class="string">"writeDataSource"</span><span>&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.apache.commons.dbcp.BasicDataSource"</span><span>&nbsp;destroy-method=</span><span class="string">"close"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"driverClassName"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"url"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.url}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"username"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.username}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"password"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.password}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"maxActive"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.maxActive}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"maxIdle"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.maxIdle}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"maxWait"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.maxWait}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&lt;/bean&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;bean id="writeDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;
&lt;property name="driverClassName"&gt;
&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="url"&gt;
&lt;value&gt;${jdbc.url}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="username"&gt;
&lt;value&gt;${jdbc.username}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="password"&gt;
&lt;value&gt;${jdbc.password}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="maxActive"&gt;
&lt;value&gt;${jdbc.maxActive}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="maxIdle"&gt;
&lt;value&gt;${jdbc.maxIdle}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="maxWait"&gt;
&lt;value&gt;${jdbc.maxWait}&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
</pre>
<br />
好了，那么在使用datasource的时候，我们应该用哪个呢，当然是writeMonitorDataSource这个里，我们可以把它注入给jdbcTemplate，或者sessionfactory，或者其他需要用到datasource的地方。 <br />
<br />
到这里，就一切准备完毕了，我们可以看看我们sql语句的执行效率了(这个页面的地址为sql.jsp)： <br />
<span style="color: darkred">见图1</span> <br />
当然要我们的应用能够显示这个页面，我们需要把jamon的一组页面拷到我们的应用中，这一组页面包含在我提供下载的包中，最新的jamon版本是2.7。 <br />
<br />
我们可以看到id为153的那条sql语句执行了78ms，我要去看看这条sql语句是不是有点什么问题或者是否有优化的可能性。 <br />
<br />
当然，刚才说到每一条sql语句都是有统计平均时间，最大最小执行时间等等，没错，在另外一个页面jamonadmin.jsp上就包含这些内容 <br />
<span style="color: darkred">见图2</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
上面的图片代表hits表示执行次数，avg表示sql执行的平均时间，后面的min和max表示sql执行的最小耗时和最大耗时。从这里我们能够更直观的看到我们每条sql语句执行的情况。很有用的一个功能。 <br />
<br />
而且在上面那两个页面上，我们还可以选择把sql执行的结果导出来，可以导成xml或excel格式。 <br />
<br />
总结：使用jamon来监控我们的sql语句我觉得很有使用意义，而且使用jamon对我们的应用来说完全是松耦合的，根本不需要更改我们的业务逻辑代码，完全是可插拔的，我们也可以开发时使用jamon，部署时拔掉jamon。有了它能够使一些程序员能够更多一点的关注自己所写的sql的效率，当然如果之前开发的时候没有使用jamon也没有关系，即使上线后也可以查看一下sql语句是否有问题，比如哪些sql语句执行得比较频繁，是否存在给其做缓存得可能性等等。总之使用jamon在应用程序中来监控我们得sql语句具有很强得实用意义， <br />
<br />
再次总结：jamon，很好，很强大。 <br />
<img src ="http://www.blogjava.net/titanaly/aggbug/327330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2010-07-28 16:06 <a href="http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C3P0连接池详细配置</title><link>http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 11 Aug 2009 09:47:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/290696.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/290696.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/290696.html</trackback:ping><description><![CDATA[&lt;<span class="hilite1">c3p0</span>-config&gt; <br />
&nbsp; &lt;default-config&gt; <br />
&lt;!--当连接池中的连接耗尽的时候<span class="hilite1">c3p0</span>一次同时获取的连接数。Default: 3 --&gt; <br />
&lt;property name="acquireIncrement"&gt;3&lt;/property&gt; <br />
<br />
&lt;!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --&gt; <br />
&lt;property name="acquireRetryAttempts"&gt;30&lt;/property&gt; <br />
<br />
&lt;!--两次连接中间隔时间，单位毫秒。Default: 1000 --&gt; <br />
&lt;property name="acquireRetryDelay"&gt;1000&lt;/property&gt; <br />
<br />
&lt;!--连接关闭时默认将所有未提交的操作回滚。Default: false --&gt; <br />
&lt;property name="autoCommitOnClose"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--<span class="hilite1">c3p0</span>将建一张名为Test的空表，并使用其自带的查询语句进行测试。如果定义了这个参数那么 <br />
&nbsp; 属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作，它将只供<span class="hilite1">c3p0</span>测试 <br />
&nbsp; 使用。Default: null--&gt; <br />
&lt;property name="automaticTestTable"&gt;Test&lt;/property&gt; <br />
<br />
&lt;!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 <br />
&nbsp; 保留，并在下次调用getConnection()的时候继续尝试获取连接。如果设为true，那么在尝试 <br />
&nbsp; 获取连接失败后该数据源将申明已断开并永久关闭。Default: false--&gt; <br />
&lt;property name="breakAfterAcquireFailure"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间，超时后将抛出 <br />
&nbsp; SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --&gt; <br />
&lt;property name="checkoutTimeout"&gt;100&lt;/property&gt; <br />
<br />
&lt;!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。 <br />
&nbsp; Default: com.mchange.v2.<span class="hilite1">c3p0</span>.impl.DefaultConnectionTester--&gt; <br />
&lt;property name="connectionTesterClassName"&gt;&lt;/property&gt; <br />
<br />
&lt;!--指定<span class="hilite1">c3p0</span> libraries的路径，如果（通常都是这样）在本地即可获得那么无需设置，默认null即可 <br />
&nbsp; Default: null--&gt; <br />
&lt;property name="factoryClassLocation"&gt;null&lt;/property&gt; <br />
<br />
&lt;!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs. <br />
&nbsp; （文档原文）作者强烈建议不使用的一个属性--&gt; <br />
&lt;property name="forceIgnoreUnresolvedTransactions"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--每60秒检查所有连接池中的空闲连接。Default: 0 --&gt; <br />
&lt;property name="idleConnectionTestPeriod"&gt;60&lt;/property&gt; <br />
<br />
&lt;!--初始化时获取三个连接，取值应在minPoolSize与maxPoolSize之间。Default: 3 --&gt; <br />
&lt;property name="initialPoolSize"&gt;3&lt;/property&gt; <br />
<br />
&lt;!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --&gt; <br />
&lt;property name="maxIdleTime"&gt;60&lt;/property&gt; <br />
<br />
&lt;!--连接池中保留的最大连接数。Default: 15 --&gt; <br />
&lt;property name="maxPoolSize"&gt;15&lt;/property&gt; <br />
<br />
&lt;!--JDBC的标准参数，用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements <br />
&nbsp; 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 <br />
&nbsp; 如果maxStatements与maxStatementsPerConnection均为0，则缓存被关闭。Default: 0--&gt; <br />
&lt;property name="maxStatements"&gt;100&lt;/property&gt; <br />
<br />
&lt;!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0&nbsp; --&gt; <br />
&lt;property name="maxStatementsPerConnection"&gt;&lt;/property&gt; <br />
<br />
&lt;!--<span class="hilite1">c3p0</span>是异步操作的，缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 <br />
&nbsp; 通过多线程实现多个操作同时被执行。Default: 3--&gt; <br />
&lt;property name="numHelperThreads"&gt;3&lt;/property&gt; <br />
<br />
&lt;!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非<span class="hilite1">c3p0</span> <br />
&nbsp; 的数据源时。Default: null--&gt; <br />
&lt;property name="overrideDefaultUser"&gt;root&lt;/property&gt; <br />
<br />
&lt;!--与overrideDefaultUser参数对应使用的一个参数。Default: null--&gt; <br />
&lt;property name="overrideDefaultPassword"&gt;password&lt;/property&gt; <br />
<br />
&lt;!--密码。Default: null--&gt; <br />
&lt;property name="password"&gt;&lt;/property&gt; <br />
<br />
&lt;!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意： <br />
&nbsp; 测试的表必须在初始数据源的时候就存在。Default: null--&gt; <br />
&lt;property name="preferredTestQuery"&gt;select id from test where id=1&lt;/property&gt; <br />
<br />
&lt;!--用户修改系统配置参数执行前最多等待300秒。Default: 300 --&gt; <br />
&lt;property name="propertyCycle"&gt;300&lt;/property&gt; <br />
<br />
&lt;!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 <br />
&nbsp; 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable <br />
&nbsp; 等方法来提升连接测试的性能。Default: false --&gt; <br />
&lt;property name="testConnectionOnCheckout"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false --&gt; <br />
&lt;property name="testConnectionOnCheckin"&gt;true&lt;/property&gt; <br />
<br />
&lt;!--用户名。Default: null--&gt; <br />
&lt;property name="user"&gt;root&lt;/property&gt; <br />
<br />
&lt;!--早期的<span class="hilite1">c3p0</span>版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数 <br />
&nbsp; 允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始 <br />
&nbsp; 广泛的被使用，所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到 <br />
&nbsp; 支持，但今后可能的版本可能不支持动态反射代理。Default: false--&gt; <br />
&lt;property name="usesTraditionalReflectiveProxies"&gt;false&lt;/property&gt; <br />
<br />
&nbsp;&nbsp;&nbsp; &lt;property name="automaticTestTable"&gt;con_test&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="checkoutTimeout"&gt;30000&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="idleConnectionTestPeriod"&gt;30&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="initialPoolSize"&gt;10&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxIdleTime"&gt;30&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxPoolSize"&gt;25&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="minPoolSize"&gt;10&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxStatements"&gt;0&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;user-overrides user="swaldman"&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;/user-overrides&gt; <br />
&nbsp; &lt;/default-config&gt; <br />
&nbsp; &lt;named-config name="dumbTestConfig"&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxStatements"&gt;200&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;user-overrides user="poop"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="maxStatements"&gt;300&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;/user-overrides&gt; <br />
&nbsp;&nbsp; &lt;/named-config&gt; <br />
&lt;/<span class="hilite1">c3p0</span>-config&gt; <br />
<img src ="http://www.blogjava.net/titanaly/aggbug/290696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-08-11 17:47 <a href="http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Communications link failure due to underlying exception</title><link>http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 11 Aug 2009 09:27:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/290691.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/290691.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/290691.html</trackback:ping><description><![CDATA[<br />
<p>最近的一个项目在Hibernate使用C3P0的连接池，数据库为Mysql。开发测试没有问题，在运行中每个一段长的空闲时间就出现异常:</p>
<br />
<ol class="dp-j">
    <li class="alt"><span><span>org.hibernate.exception.JDBCConnectionException: could not execute query </span></span>
    <li class=""><span>at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:</span><span class="number">74</span><span>) </span>
    <li class="alt"><span>at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:</span><span class="number">43</span><span>) </span>
    <li class=""><span>....... </span>
    <li class="alt"><span>Caused by: com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed <span class="hilite4">due</span> <span class="hilite5">to</span> <span class="hilite6">underlying</span> exception/error: </span>
    <li class="">
    <li class="alt">
    <li class=""><span>** BEGIN NESTED EXCEPTION ** </span>
    <li class="alt">
    <li class=""><span>com.mysql.jdbc.CommunicationsException </span>
    <li class="alt"><span>MESSAGE: <span class="hilite1">Communications</span> <span class="hilite2">link</span> <span class="hilite3">failure</span> <span class="hilite4">due</span> <span class="hilite5">to</span> <span class="hilite6">underlying</span> exception: </span>
    <li class="">
    <li class="alt"><span>** BEGIN NESTED EXCEPTION ** </span>
    <li class="">
    <li class="alt"><span>java.net.SocketException </span>
    <li class=""><span>MESSAGE: Broken pipe </span>
    <li class="alt">
    <li class=""><span>STACKTRACE: </span>
    <li class="alt">
    <li class=""><span>java.net.SocketException: Broken pipe </span>
    <li class="alt"><span>at java.net.SocketOutputStream.socketWrite0(Native Method) </span>
    <li class=""><span>...... </span>
    <li class="alt"><span>** END NESTED EXCEPTION ** </span></li>
</ol>
<span>
<p>查看了Mysql的文档，以及Connector/J的文档以及在线说明发现，出现这种异常的原因是：</p>
<p>Mysql服务器默认的&#8220;wait_timeout&#8221;是8小时，也就是说一个connection空闲超过8个小时，Mysql将自动断开该connection。这就是问题的所在，在C3P0 pools中的connections如果空闲超过8小时，Mysql将其断开，而C3P0并不知道该connection已经失效，如果这时有Client请求connection，C3P0将该失效的Connection提供给Client，将会造成上面的异常。</p>
<p>解决的方法有3种：</p>
<ol>
    <li>增加wait_timeout的时间。
    <li>减少Connection pools中connection的lifetime。
    <li>测试Connection pools中connection的有效性。 </li>
</ol>
<p>当然最好的办法是同时综合使用上述3种方法，下面就DBCP和C3P0分别做一说明，假设wait_timeout为默认的8小时</p>
<p>DBCP增加以下配置信息:</p>
<li class="alt"><span><span class="comment">//set <span class="hilite5">to</span> 'SELECT 1' </span></span>
<li class=""><span>validationQuery = </span><span class="string">"SELECT 1"</span><span> </span>
<li class="alt"><span><span class="comment">//set <span class="hilite5">to</span> 'true' </span></span>
<li class=""><span>testWhileIdle = </span><span class="string">"true"</span><span> </span>
<li class="alt"><span><span class="comment">//some positive integer </span></span>
<li class=""><span>timeBetweenEvictionRunsMillis = </span><span class="number">3600000</span><span> </span>
<li class="alt"><span><span class="comment">//set <span class="hilite5">to</span> something smaller than 'wait_timeout' </span></span>
<li class=""><span>minEvictableIdleTimeMillis = </span><span class="number">18000000</span><span> </span>
<li class="alt"><span><span class="comment">//if you don't mind a hit for every getConnection(), set <span class="hilite5">to</span> "true" </span></span>
<li class=""><span>testOnBorrow = </span><span class="string">"true"</span><span> </span>
<p class="alt"><br />
<br />
<br />
C3P0增加以下配置信息:<br />
</span>&nbsp;</p>
<li class="alt"><span><span class="comment">//获取connnection时测试是否有效</span>
<li class=""><span>testConnectionOnCheckin = true</span>
<li class=""><span>//自动测试的table名称<br />
</span>
<li class=""><span>automaticTestTable=C3P0TestTable<br />
</span>
<li class="alt"><span class="comment">//set <span class="hilite5"><span class="hilite5"><span class="hilite5">to</span></span></span> something much less than wait_timeout, prevents connections from going stale </span>
<li class=""><span>idleConnectionTestPeriod = </span><span class="number">18000</span><span> </span>
<li class="alt"><span><span class="comment">//set <span class="hilite5"><span class="hilite5"><span class="hilite5">to</span></span></span> something slightly less than wait_timeout, preventing 'stale' connections from being handed out </span></span>
<li class=""><span>maxIdleTime = </span><span class="number">25000</span><span> </span>
<li class="alt"><span><span class="comment">//if you can take the performance 'hit', set <span class="hilite5"><span class="hilite5"><span class="hilite5">to</span></span></span> "true" </span></span>
<li class=""><span>testConnectionOnCheckout = </span><span class="keyword">true</span><span> </span></li>
<p class="">&nbsp;</p>
<p class="">&nbsp;</p>
<p class="">&nbsp;</p>
<p class=""><span style="color: red">在配置文件中要写成&nbsp; &lt;property name="minPoolSize"&gt;&lt;value&gt;1&lt;/value&gt;&lt;/property&gt; 格式</span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">不能写成 这样&lt;property name="properties"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;props&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;prop key="c3p0.initialPoolSize"&gt;1&lt;/prop&gt;</span></span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">&nbsp;&nbsp;&nbsp;&lt;/props&gt;</span></span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">&lt;/property&gt;</span></span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">c3p0不能完全识别!!</span></span></span></p>
<img src ="http://www.blogjava.net/titanaly/aggbug/290691.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-08-11 17:27 <a href="http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>