c3p0 - CLOSE BY CLIENT STACK TRACE

由一个DEBUG说开去

先交代一下背景。前端

昨天晚上一个群友在群里问我一个问题。他当时在给Oracle 10g配置C3P0链接池。最起初呢,这家伙用的是ojdbc14.jar。写法是标准的Spring的写法,可是就是不行。后来我说,你换个包。换成classes12.jar看看。顺利执行了。java

话说,后来又出了一个问题。他问我说,执行是执行了,可是出现个新的问题。程序员

XXXX(1234567890123456) 19:02:17
新问题又出来了sql

XXXX(1234567890123456) 19:02:28数据库

NewPooledConnection - closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyRe
source(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:96
4)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.ja
va:547)
C3P0PooledConnectionPool - Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewPool编程

我看到那个DEBUG,我说,是调试信息,修改一下LOG4J的等级就好了。app

这个群友很不解的问,既然成功了,干吗还要丢异常出来?async

这里就不得不说到两个商业开发的原则问题了。ide

第一,对上家传入数据严加过滤,对传出给下家的数据仔细检查。模块化

第二,合理使用异常。

第一点其实很简单的。也就是模块化开发的一个思想问题。对本身的行为负责。前端返回的数据到底是什么,须要进行校验。不合格的剔除或者是修正。合格的处理完后,在传出以前也要加以校验,是否合格。

具体到这个问题里,就是来自Spring关于数据源的那个配置文件。

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

//略去数据源相关信息的配置

</bean>

这个配置文件里,有两个信息是很管用的。一个是class,一个是destroy-method。简单点说,一个是数据源的实现类,一个是析构方法。Spring在读取这个配置文件之后,须要根据这些信息来实例化一些类,而后内部再根据中间的那些配置信息来实际构造数据源。好比username啥的。

但是来了个问题。不能保证这里的ComboPooledDataSource数据源必定是可用的,也不能保证close方法必定能关闭链接,对吧?Spring自己不能检查这个类是否真实有效,毫无Bug。实际上呢,也检查不了。一样的,close方法是否有效,也须要进行检查。这就是我刚才说的,对上家数据的严加检查。

那好吧,怎么检查呢?最简洁的方法莫过于实际构造一下,链接池,获取数据库链接,执行一个测试语句,而后关闭链接。若是一切都成功,那就OK。关于那个测试语句,配置过WebSphere数据源的同窗们还记得不?有个SQL语句会默认的写在数据源配置里,是 " SELECT 1 FROM TABLE "。嗯,对的,这个就是测试语句。

这一套流程能走得通,走的顺,那么就能够在本身能力范围内说这个数据源和链接池是能用的,对吧?

这里补充一个知识。java.sql.Connection,这玩意不是class,是interface。

声明是:public interface Connection extends Wrapper 。

任何一个JDBC数据库链接的实现类都应该实现这个接口的所有方法。好比,close。API里的描述是,当即释放此 Connection 对象的数据库和 JDBC 资源,而不是等待它们被自动释放。

熟悉Java的同窗们应该记得一点,在规范里有个要求,就是接口的实现类必须实现接口的全部方法。可是呢,这句话还有个意思,那就是,你能够在实现全部方法以外,再写几个方法。没人会管你。

啊哈,那就有疑问了。虽然API规定了close是关闭链接释放资源的。但这只是你接口的一厢情愿。也许人家实现厂家以为close方法不够帅,要改为closeConnection。那。。。Spring总很差傻傻的去死扣close方法来关闭链接吧?虽然这方法必须实现,可是可没说必定要有内容啊。若是是空方法呢?

因此有了destroy-method这个配置项的出现。Spring说,不碍的,您老人家看哪一个爽,告诉我就行。

如今测试完了。一切都成功了。

如今来看看第二个问题。合理使用异常。

又遇到一个问题。既然测试成功了,那总得给用户一点交待吧?难道说,测试成功了,就闷声大发财了?显然不合适嘛。能够试想一下,你是程序员,而后点了个按钮,测试。结果呢,其实是测试成功了,可是系统啥动静都不给你。而后你傻傻的等痴痴的盼,一直等到天荒地老……嗯嗯,扯的有点远。若是你等一个小时还不见动静,活不见人死不见尸的,你说你会不会骂娘?

那么怎么通知才能保证必定有效呢?println?这个不见得必定能看到。由于别人也可能在同时输出信息,一下就刷掉了。那么有同窗说了,最好是能暂停一下,我输出之后,就暂停了,不动了。

嗯,很好。

你们想一想看,输出一大堆东西,而后此程序不动了,不继续执行了,这是啥玩意?

这不就是异常嘛!

只有异常能保证程序员必定能看到这个信息,好比,测试成功。这就是为何Spring要采用这种方式来通知的缘由。

这里呢,我想更正同窗们一个习惯成天然的想法。异常不必定是通知坏消息的。异常就是异常,只要你愿意,你甚至能够在代码执行成功的时候,throws一个Exception。异常只不过是比较激烈的一种通知方式而已。无他,仅此而已。

如今又有个问题来了。既然要测试,并且每次执行到此处的时候都要测试一下。那么……难道都卡在这里不走了啊?显然更不合适啊。

熟悉log4J的同窗应该看出来了,这是log4J输出的日志。很明显的,这种日志只应当在开发期间存在,不该该在发布期间存在。由于开发期间数据库变更很大,好比改表啊,改数据库配置啊。因此须要通知用户是否成功。可是产品一旦开发完毕,正式发布,这种信息就不该再出现,由于商业化运做的应用不容许乱动配置的,对不?

因此log4J提供了一种方法。消息级别。INFO的时候,是看不到这个异常的。实现起来也很好办,catch了,而后不作任何处理,也就是空的catch块。

具体实现的时候能够在catch里判断一下,若是等级是INFO的话,就不作任何事。若是不是,那就按照规则去作。

结合到 “合理使用异常” 这句话来讲呢,就是说,须要抛出异常的时候,就抛出。不须要抛出的时候,就不抛出。对程序员来讲,在必要的时候看到一串异常信息,是最合适的事情了。

关于异常的使用,这里不展开说了。有兴趣的同窗能够参见林锐博士的 高质量Java编程。

相关文章
相关标签/搜索