java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE 的理解
[2013-12-06 11:06:21,715] [C3P0PooledConnectionPoolManager[identityToken->2tl0n98y1iwg7cbdzzq7a|719f1f]-HelperThread-#2] DEBUG - com.mchange.v2.c3p0.impl.NewPooledConnection@484c6b closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:646)
at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:259)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:619)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1024)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
[2013-12-06 11:06:21,716] [C3P0PooledConnectionPoolManager[identityToken->2tl0n98y1iwg7cbdzzq7a|719f1f]-HelperThread-#2] DEBUG - Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@484c6b
经过分析源码,得到的结论是这个异常可以无视掉。
相关源码如下(c3p0版本:c3p0-0.9.2.1):
package com.mchange.v2.c3p0.impl; import java.util.*; import java.sql.*; import javax.sql.*; import com.mchange.v2.c3p0.*; import com.mchange.v2.c3p0.stmt.*; import com.mchange.v2.c3p0.util.*; import com.mchange.v2.log.*; import java.lang.reflect.Method; import com.mchange.v2.lang.ObjectUtils; import com.mchange.v2.sql.SqlUtils; public final class NewPooledConnection extends AbstractC3P0PooledConnection{ private final static MLogger logger = MLog.getLogger( NewPooledConnection.class );
// methods below must be called from sync'ed methods /* * If a throwable cause is provided, the PooledConnection is known to be broken (cause is an invalidating exception) * and this method will not throw any exceptions, even if some resource closes fail. * * If cause is null, then we think the PooledConnection is healthy, and we will report (throw) an exception * if resources unexpectedlay fail to close. */ private void close( Throwable cause ) throws SQLException { close( cause, false ); } private void close( Throwable cause, boolean forced ) throws SQLException { assert Thread.holdsLock( this ); if ( this.invalidatingException == null ) { List closeExceptions = new LinkedList(); // cleanup ResultSets cleanupResultSets( closeExceptions ); // cleanup uncached Statements // System.err.println(this + ".close( ... ) -- uncachedActiveStatements: " + uncachedActiveStatements); cleanupUncachedStatements( closeExceptions ); // cleanup cached Statements try { closeAllCachedStatements(); } catch ( SQLException e ) { closeExceptions.add(e); } if ( forced ) { // reset transaction state try { C3P0ImplUtils.resetTxnState( physicalConnection, forceIgnoreUnresolvedTransactions, autoCommitOnClose, false ); } catch (Exception e) { if (logger.isLoggable( MLevel.FINER )) logger.log( MLevel.FINER, "Failed to reset the transaction state of " + physicalConnection + "just prior to close(). " + "Only relevant at all if this was a Connection being forced close()ed midtransaction.", e ); } } // cleanup physicalConnection try { physicalConnection.close(); } catch ( SQLException e ) { if (logger.isLoggable( MLevel.FINER )) logger.log( MLevel.FINER, "Failed to close physical Connection: " + physicalConnection, e ); closeExceptions.add(e); } // update our state to bad status and closed, and log any exceptions if ( connection_status == ConnectionTester.CONNECTION_IS_OKAY ) connection_status = ConnectionTester.CONNECTION_IS_INVALID; if ( cause == null ) { this.invalidatingException = NORMAL_CLOSE_PLACEHOLDER; if ( Debug.DEBUG && logger.isLoggable( MLevel.FINEST ) ) logger.log( MLevel.FINEST, this + " closed by a client.", new Exception("DEBUG -- CLOSE BY CLIENT STACK TRACE") );//num:646 in the NewPooledConnection.java /*Note that:
1、This is not an exception, the new Exception is used merely to show execution path for debug purposes.
2、And yes, this is only a debug message (actually, FINEST is the lowest possible level in java.util.logging).
To wrap this up: ignore and tune your logging levels to skip these.http://stackoverflow.com/questions/8403227/weird-error-close-by-client-stack-trace
既然成功了,干嘛还要丢异常出来?
这里就不得不说到两个商业开发的原则问题了。
第一,对上家传入数据严加过滤,对传出给下家的数据仔细检查。
第二,合理使用异常。
第一点其实很简单的。也就是模块化开发的一个思想问题。对自己的行为负责。前端返回的数据究竟是什么,需要进行校验。不合格的剔除或者是修正。合格的处理完后,在传出之前也要加以校验,是否合格结合到 “合理使用异常” 这句话来说呢,就是说,需要抛出异常的时候,就抛出。不需要抛出的时候,就不抛出。对程序员来说,在必要的时候看到一串异常信息,是最合适的事情了。
http://www.zhixing123.cn/jsp/23305.html
*/
logCloseExceptions( null, closeExceptions ); if (closeExceptions.size() > 0) throw new SQLException("Some resources failed to close properly while closing " + this); } else { this.invalidatingException = cause; if (Debug.TRACE >= Debug.TRACE_MED) logCloseExceptions( cause, closeExceptions ); else logCloseExceptions( cause, null ); } } }
相关类:
/******************************************************************** * This class generated by com.mchange.v2.debug.DebugGen * and will probably be overwritten by the same! Edit at * YOUR PERIL!!! Hahahahaha. ********************************************************************/ package com.mchange.v2.c3p0.impl; import com.mchange.v2.debug.DebugConstants; final class Debug implements DebugConstants { final static boolean DEBUG = true; final static int TRACE = TRACE_MAX; private Debug() {} }
package com.mchange.v2.log; import java.util.*; public final class MLevel { public final static MLevel ALL; public final static MLevel CONFIG; public final static MLevel FINE; public final static MLevel FINER; public final static MLevel FINEST; public final static MLevel INFO; public final static MLevel OFF; public final static MLevel SEVERE; public final static MLevel WARNING; private final static Map integersToMLevels; private final static Map namesToMLevels; public static MLevel fromIntValue(int intval) { return (MLevel) integersToMLevels.get( new Integer( intval ) ); } public static MLevel fromSeverity(String name) { return (MLevel) namesToMLevels.get( name ); } static { Class lvlClass; boolean jdk14api; //not just jdk14 -- it is possible for the api to be present with older vms try { lvlClass = Class.forName( "java.util.logging.Level" ); jdk14api = true; } catch (ClassNotFoundException e ) { lvlClass = null; jdk14api = false; } MLevel all; MLevel config; MLevel fine; MLevel finer; MLevel finest; MLevel info; MLevel off; MLevel severe; MLevel warning; try { // numeric values match the intvalues from java.util.logging.Level all = new MLevel( (jdk14api ? lvlClass.getField("ALL").get(null) : null), Integer.MIN_VALUE, "ALL" ); config = new MLevel( (jdk14api ? lvlClass.getField("CONFIG").get(null) : null), 700, "CONFIG" ); fine = new MLevel( (jdk14api ? lvlClass.getField("FINE").get(null) : null), 500, "FINE" ); finer = new MLevel( (jdk14api ? lvlClass.getField("FINER").get(null) : null), 400, "FINER" ); finest = new MLevel( (jdk14api ? lvlClass.getField("FINEST").get(null) : null), 300, "FINEST" ); info = new MLevel( (jdk14api ? lvlClass.getField("INFO").get(null) : null), 800, "INFO" ); off = new MLevel( (jdk14api ? lvlClass.getField("OFF").get(null) : null), Integer.MAX_VALUE, "OFF" ); severe = new MLevel( (jdk14api ? lvlClass.getField("SEVERE").get(null) : null), 900, "SEVERE" ); warning = new MLevel( (jdk14api ? lvlClass.getField("WARNING").get(null) : null), 1000, "WARNING" ); } catch ( Exception e ) { e.printStackTrace(); throw new InternalError("Huh? java.util.logging.Level is here, but not its expected public fields?"); } ALL = all; CONFIG = config; FINE = fine; FINER = finer; FINEST = finest; INFO = info; OFF = off; SEVERE = severe; WARNING = warning; Map tmp = new HashMap(); tmp.put( new Integer(all.intValue()), all); tmp.put( new Integer(config.intValue()), config); tmp.put( new Integer(fine.intValue()), fine); tmp.put( new Integer(finer.intValue()), finer); tmp.put( new Integer(finest.intValue()), finest); tmp.put( new Integer(info.intValue()), info); tmp.put( new Integer(off.intValue()), off); tmp.put( new Integer(severe.intValue()), severe); tmp.put( new Integer(warning.intValue()), warning); integersToMLevels = Collections.unmodifiableMap( tmp ); tmp = new HashMap(); tmp.put( all.getSeverity(), all); tmp.put( config.getSeverity(), config); tmp.put( fine.getSeverity(), fine); tmp.put( finer.getSeverity(), finer); tmp.put( finest.getSeverity(), finest); tmp.put( info.getSeverity(), info); tmp.put( off.getSeverity(), off); tmp.put( severe.getSeverity(), severe); tmp.put( warning.getSeverity(), warning); namesToMLevels = Collections.unmodifiableMap( tmp ); } Object level; int intval; String lvlstring; public int intValue() { return intval; } public Object asJdk14Level() { return level; } public String getSeverity() { return lvlstring; } public String toString() { return this.getClass().getName() + this.getLineHeader(); } public String getLineHeader() { return "[" + lvlstring + ']';} public boolean isLoggable( MLevel filterLevel ) { return this.intval >= filterLevel.intval; } private MLevel(Object level, int intval, String lvlstring) { this.level = level; this.intval = intval; this.lvlstring = lvlstring; } }
package java.util.logging;
import java.util.*;
import java.security.*;
import java.lang.ref.WeakReference;
private static final int offValue = Level.OFF.intValue();
private volatile int levelValue; // current effective level value
/** * Check if a message of the given level would actually be logged * by this logger. This check is based on the Loggers effective level, * which may be inherited from its parent. * * @param level a message logging level * @return true if the given message level is currently being logged. */ public boolean isLoggable(Level level) { if (level.intValue() < levelValue || levelValue == offValue) { return false; } return true; }