专栏首页卯金刀GGc3p0之DEBUG -- CLOSE BY CLIENT STACK TRACE

c3p0之DEBUG -- CLOSE BY CLIENT STACK TRACE

本文转载自:http://blog.csdn.net/rchm8519/article/details/40147745

项目使用C3P0数据库连接池,最近发现一个Exception:

10:22:25.962 [Timer-0] DEBUG c.m.v.resourcepool.BasicResourcePool - incremented pending_acquires: 1 10:22:25.962 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] DEBUG c.m.v.c.i.C3P0PooledConnectionPool - Preparing to destroy PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@3c508c99 10:22:25.963 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] DEBUG c.m.v2.c3p0.impl.NewPooledConnection - com.mchange.v2.c3p0.impl.NewPooledConnection@3c508c99 closed by a client. java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566) [c3p0-0.9.1.2.jar:0.9.1.2] at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234) [c3p0-0.9.1.2.jar:0.9.1.2] at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:470) [c3p0-0.9.1.2.jar:0.9.1.2] at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:964) [c3p0-0.9.1.2.jar:0.9.1.2] at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547) [c3p0-0.9.1.2.jar:0.9.1.2] 10:22:25.963 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] DEBUG c.m.v.c.i.C3P0PooledConnectionPool - Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@3c508c99 10:22:25.963 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] DEBUG c.m.v.resourcepool.BasicResourcePool - Successfully destroyed resource: com.mchange.v2.c3p0.impl.NewPooledConnection@3c508c99

并未发现该异常并未对系统的运行造成什么影响,网上也说,关掉debug级别的日志就可以啦,确实,一个放在debug级别里的异常想来也不会是什么重要异常!但由于好奇心驱使还是止不住想要弄清其来龙去脉!

于是在网上搜到下面这样一篇日志,受益匪浅,分享给大家,在此对作者表示感谢。

转文地址:http://blog.csdn.net/rchm8519/article/details/40147745

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的等级就行了。

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

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

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

第二,合理使用异常。

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

具体到这个问题里,就是来自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编程。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 开发 7 年,我学到了什么?

    oschina.net/news/106798/7-years-as-a-developer-lessons-learned

    Java技术栈
  • MYSQL vs JAVA 连接错误

    最近开发告诉我,他们在测试系统的时候,会经常有连接MYSQL的连接被踢掉。具体给我的解释是,JAVA的缓冲池连接MYSQL 保持连接,但再次使用的时候,报连接错...

    AustinDatabases
  • 『互联网架构』软件架构-分布式集中配置中心Spring Cloud Config详解(上)(103)

    PS:分布式集中配置中心Spring Cloud Config 确实功能很强大,这次咱们主要说下,如果制作server,client端如何获取,而且还说了加密和...

    IT故事会
  • java:组播通讯示例

    在局域网内,组播通讯还是很有用处的,以下代码基于MulticastSocket类进一步封装更加方便的实现组播数据发送和组播数据接收功能。

    用户1148648
  • Java8新特性:Lambda表达式详解

    在 Java 版本的历次更新迭代中,Java8 是一个特殊的存在,与以往的版本升级不同。我们对 Java8 似乎抱有更大的期待,因为它是 Java5 之后最重要...

    南风
  • 本人andriod开发,一直害怕有一天领导让我接fpga开发,而我年龄大,怎么办?

    开发安卓距离fpga还是有点距离,这个问题还是显得有点让人捉摸不透,安卓开发本身也分为几种情况,安卓底层开发,安卓框架层开发,安卓应用级别的开发,安卓底层开发主...

    程序员互动联盟
  • Netty 如何实现心跳机制与断线重连?

    所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性.

    Java技术栈
  • Java常用的几个Json库,性能强势对比!

    https://xncoding.com/2018/01/09/java/jsons.html

    Java技术栈
  • Java反射从放弃到入门

    Java反射特性提供了在运行时可以动态访问和修改类和实例内部的状态的功能。反射是Java语言里面一个高级的话题之一,使用反射我们可以在运行时轻松的内省一个类,接...

    我是攻城师
  • java和python哪个未来发展比较好?

    从事软件开发多年,java代码写得稍微多点,python只是在作为脚本处理一些数据的时候用到,不过从目前的编程语言的发展态势看,python的风头更加强劲一些,...

    程序员互动联盟

扫码关注云+社区

领取腾讯云代金券