proxool.FatalSqlExceptionHelper.testException()

我终于找到了出问题的线程了。


通过thread dump 我发现如下线程一直在运行:
“resin-tcp-connection-*:80-6075” daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable [0x82dfe000..0x82dff19c]
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:103)
at org.logicalcobwebs.proxool.AbstractProxyStatement.testException(AbstractProxyStatement.java:65)
at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:146)
at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
at $java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
at com.tag.db.doEndTag(valuetag.java:438)
at _jsp._rst._eng_0aa__jsp._jspService(_products_0viewinfo__jsp.java:75)
at com.caucho.jsp.JavaPage.service(JavaPage.java:60)
at com.caucho.jsp.Page.pageservice(Page.java:570)
at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:159)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:267)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:388)
– locked <0x5c472008> (a java.lang.Object)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:490)
at com.caucho.util.ThreadPool.run(ThreadPool.java:423)
at java.lang.Thread.run(Thread.java:595)


然后我又查看了顶级的代码调用
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
也就是testException这个方法一直在执行,我不清楚为什么为会出现如此死循环。


我想问问大家,什么样的代码会导致proxool的testException一直运行着。



——————————————————————————–


不知道是分数不够,还是人才稀少,怎么就没人回答呢。郁闷


——————————————————————————–


为什么会重复出现:
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
谁能告诉我啊。


——————————————————————————–


本来proxool是很有口碑的连接池 ,怎么会导致


at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)中testException运行没完没了呢。


——————————————————————————–


努力接分升级中…帮你up!


——————————————————————————–


filter 死循环调用?


——————————————————————————–


回复:iihero(阿黑哥)


应该不是filter的引起的,如果是filter的话,那所有的页面都会很容易进入死循环。


——————————————————————————–


下面就是这个永远不结束的方法,我看了一下源代码,虽然有循环部分,但也不导致死循环,
大伙帮我分析一下,具体是什么原因会导致下面的代码一直执行?
/**
* Test to see if an exception is a fatal one
* @param cpd the definition so we can find out what a fatal exception looks like
* @param t the exception to test
* @param level the recursion level (max 20)
* @return true if it is fatal
*/
protected static boolean testException(ConnectionPoolDefinitionIF cpd, Throwable t, int level) {
boolean fatalSqlExceptionDetected = false;
Iterator i = cpd.getFatalSqlExceptions().iterator();
while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}


// If it isn’t fatal, then try testing the contained exception
if (!fatalSqlExceptionDetected && level < 20) {
Throwable cause = getCause(t);
if (cause != null) {
fatalSqlExceptionDetected = testException(cpd, cause, level + 1);
}
}


return fatalSqlExceptionDetected;
}


——————————————————————————–


while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}


t.getMessage() != null这句话不成立的话,就没机会调用i.next()
就死循环了。


——————————————————————————–


在网上大家都对proxool赞赏有加,但是我们的项目出现如此严重的错误,实属不应该,
请兄弟们帮我查明此原因,不让我再去怀疑proxool的过错了,把清白留proxool。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


t.getMessage() != null不成立,也应该会再次调用i.hasNext()吧


——————————————————————————–


请大伙帮我把铁顶起来,都快两天了,还是没找到答案。


——————————————————————————–


你说的错了,&& 运算是从左到右,左边的不成立,直接就返回false了,不再计算右边的。所以不调用i.next()。


楼主要加强基础。


——————————————————————————–


你可以写个小例子测试一下。


——————————————————————————–


当 t.getMessage() != null不成立时,是“t.getMessage().indexOf((String) i.next()) > -1”没机会执行。不是i.hasNext


——————————————————————————–


回复: zhmt(不爽你就用分砸我!!!)


我还是不明白,t.getMessage() != null这句话不成立的话,就会导致死循环。


——————————————————————————–


就算“t.getMessage().indexOf((String) i.next()) > -1不知道,也不会导致死循环啊。


——————————————————————————–


我上面的那段代码是从proxool中取出来的,如果这么容易就死循环了,那我就要怀疑这个东西的安全性啦。


——————————————————————————–


你的问题的背景是什么啊?
不能光看这一点。


——————————————————————————–


resin-tcp-connection-*:80-6075″ daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable


这是个守护线程,(daemon),一直运行的话,是很正常的。可能问题不在这里,你的是什么性能问题啊?


——————————————————————————–


好,那我就说说背景 :


我维护的是个网站项目,网站经常服务器cpu 99%,并且上去了就不下来了,开始我就确定是
死循环的问题,但是找不到根据,前两天我用kill -3 pid,每隔5分钟Thread Dump一下,发现
上面的线程一直在虚拟机(JVM)里面运行者。那只有死循环才不会退出的。
我不知道我讲清楚没?


——————————————————————————–


daemon是守护进程,但是不应该不结束。


——————————————————————————–


你确信是这个线程启动后cpu才到100%的吗?


——————————————————————————–


是的。在平时,我找不到这样的线程。


——————————————————————————–


我查了一下它的源码,这个类是用来检查一个异常是否是严重异常,它能一直运行说明你的应用导致了很多sql异常。如果这个pool是经过大家的检验的话,可能你的应用中,哪一部分的sql调用很有问题。


——————————————————————————–


是的,但是很多异常也会有个数量限制啊,可能处理校验的速度慢啊,而不会出现,死循环啊。
在页面上传入的sql语句难免有些问题,我测试过,一般情况下,系统会自动处理的,但是我想在就不明白,什么情况下,什么样的SQL语句会导致死循环。


——————————————————————————–


你看了有多少个这样线程了吗?
可能不是死循环,而是线程结束后又被启动起来。或者是启动了多个这样的线程。
如果不是我感才说的那个死循环的,就不可能出现死循环了(next和hasNext要成对使用才不会死在那,如果只使用hasNext而不使用next,那么iterator是不往下走的,就会死了。)。
另外它的递归调用也不会超过20层,所以也不会死。


——————————————————————————–


我觉得从自己的应用上来改进应该更好。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


你说的有道理,如果 t.getMessage() ==null的话,就会陷入死循环。


但是我看我们的代码都是按照JDBC规范来写的啊。


下面我贴些原码,帮我看看有什么问题。


 


——————————————————————————–


public HashMap getdbValue(PoolBean pool) throws Exception
{
if(pool.getLog().isDebugEnabled())
pool.getLog().debug(“star getdbValue”);


String system_name = pool.getDatabaseInfo().getSystemName();
HashMap result = null;
String temp_sql = createSql();
if(temp_sql == null)
throw new SQLException(“not sql statement”);


Statement stmt = null;
ResultSet rs = null;
Connection con = null;
try
{
con = pool.getNoInfoConnection();// .getConnection();
con.setReadOnly(true);
stmt = con.createStatement();
rs = stmt.executeQuery(temp_sql);
// rs = stmt.executeQuery(sql);
if (rs != null) {
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
if (rs.next()) {
result = new HashMap();
for (int i = 1; i <= colCount; i++) {
String name = rsmd.getColumnName(i);
name = name.toLowerCase();
String type_name = rsmd.getColumnTypeName(i).toLowerCase();
// System.out.println(“field name : ” + name + ” , type_anme : ” + type_name);
if (“text”.equals(type_name)) {
//当字段类型为text时,如果直接用rs.getObject(i)取数据,在jtds1.0版本中不能直接取出,改为以下方式即可 2005-07-22 张贵平
String tt_str = rs.getString(i);
// System.out.println(“text — “+tt_str);
if (tt_str == null)
tt_str = “”;
else
tt_str = tt_str.trim();
result.put(name.trim(), tt_str);
}
else {
Object obj_value = rs.getObject(i);
if (obj_value instanceof java.lang.String) {
String t_str = null;
if (obj_value == null)
t_str = “”;
else
t_str = String.valueOf(obj_value).trim();
result.put(name.trim(), t_str);
}
else {
result.put(name.trim(), obj_value);
}
}
}
}
rsmd = null;
}
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();
}
catch(SQLException e)
{
//CloseCon.Close(con);
pool.getLog().error(system_name+”,”+e.getMessage()+”,sql:”+temp_sql);
throw new SQLException(“database perform error : ” + e.getMessage());
}
finally
{
CloseCon.Close(con);
}


return result;


}


从线程堆栈上看$java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
,是从stmt.close()进去的。



——————————————————————————–


觉得不规范
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();


以上这些东西都要放在finnally块中的。


我没用过PoolBean,不知道怎么用,觉得数据库的操作好像没多大问题。你倒网上搜索资料看看吧。


——————————————————————————–


你看下Filter里面的跳转是不是错了。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


PoolBean 是我们自己写的一个类,主要是做跟连接池的衔接工作。


是的,不是很规范,但是这样也应该不会导致proxool死循环。


——————————————————————————–


我们自己的Filter类,看看有什么问题。


public class SetCharacterEncodingFilter implements Filter {


Log log = LogFactory.getLog(this.getClass().getName());


// —————————————————– Instance Variables


/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;



/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;


/**
* 上传文件的最大大小
*/
protected int fileMaxLength = 200*1024; //200K


/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;



/**
* Take this filter out of service.
*/
public void destroy() {


this.encoding = null;
this.filterConfig = null;


}



/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {


// Conditionally select and set the character encoding to be used


HttpServletRequest t_re = (HttpServletRequest) request;


String re_uri = trimString(t_re.getRequestURI());
String re_host = trimString(t_re.getServerName());
String qu_str = trimString(t_re.getQueryString());



if (re_uri.indexOf(“.do”) > 0)
{
if (log.isInfoEnabled())
log.info(re_host + re_uri + “?” + qu_str);


try
{


if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
catch(Exception e)
{
// e.printStackTrace();
String error_mes = e.getMessage();
String strServerName = null;
String strQueryString = null;
String requestUrl = null;
String remoteAddr = null;
String referer = “”;
if(error_mes.indexOf(“reset”)<0 )
{
try {
strServerName = t_re.getServerName();
strQueryString = t_re.getQueryString();
requestUrl = t_re.getRequestURI();
// strQueryString = CodeTransfer.ISOToUnicode(strQueryString);
referer = t_re.getHeader(“referer”);
remoteAddr = t_re.getRemoteAddr();
}
catch (Exception e1) {}
if (error_mes != null && !”null”.equals(error_mes)&& error_mes.length() > 0) {
log.error(“,exception:” +
error_mes + strServerName + ” , ” + strQueryString + ” , ” +
requestUrl + ” , ” + referer);
// System.out.println(“exception at filter:” +
// error_mes);
}


}
if(log.isInfoEnabled())
log.info(strServerName + ” , ” + strQueryString+ ” , ” + requestUrl + ” , ” + referer);
}


}



/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {


this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter(“encoding”);
String value = filterConfig.getInitParameter(“ignore”);
String file_max_length = filterConfig.getInitParameter(“file_max_length”);
if(file_max_length!=null && file_max_length.length() >0)
{
fileMaxLength = com.kenfor.util.MyUtil.getStringToInt(file_max_length,200)*1024;
}


if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase(“true”))
this.ignore = true;
else if (value.equalsIgnoreCase(“yes”))
this.ignore = true;
else
this.ignore = false;


}


/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* null.
*


* The default implementation unconditionally returns the value configured
* by the encoding initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {


return (this.encoding);


}
private String trimString(String value)
{
String result = “”;
if(value !=null)
result = value.trim();


return result;
}



}


 


 


——————————————————————————–


如果真的是proxool,那我应该感到欣慰,如果是我们写的代码不当引起的,但我就真的无地之容了。


——————————————————————————–


呵呵,这个我也搞不清楚,楼主最好把你们的那个poolBean自己测试一下。
能找到那种情况下出那个错误是最好的。


看看循环使用的时候是否也抛出这个异常,如果这样的话就查查哪的问题吧。如果不出错,可能就是sql写的有问题了。


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.