多线程问题导致的JDBMonitor的bug分析

发表于:2008-10-08来源:作者:点击数: 标签:bugBUGBug线程JDBMonitor
关键字: 以前我一直是用使用数据源的 系统测试 JDBMonitor,昨天我准备把JDBMonitor嵌入到一个小的jsp留言板中,这个留言板写的非常简单, 数据库 操作也是connection随取随用、用完了就关这种最简单的形式,这倒是帮助我发现了一个超级大 bug 。 在记事本
关键字:

以前我一直是用使用数据源的系统测试JDBMonitor,昨天我准备把JDBMonitor嵌入到一个小的jsp留言板中,这个留言板写的非常简单,数据库操作也是connection随取随用、用完了就关这种最简单的形式,这倒是帮助我发现了一个超级大bug
在记事本运行中常常不规律的DataBaseDBListener的logSQL方法报空指针错误,是在logStatement.setString(1, randomGUID.toString());这一句抛出的,我跟踪到mysql驱动的内部(我使用的是mysql数据库做DataBaseDBListener的输出数据库),发现在setString的实现中会去调用connection的方法,而此时connection已经是null了,所以会报空指针错误。
从其不规律的特点我判断出应该是多线程导致的问题。我跟踪发现,有的时候是先调用DataBaseDBListener的close后logSql才被调用。经过分析找出了问题所在,问题就在DBLogger中内部类LogConsumer的startConsumer方法,这个是修改以前的代码:
for (;;)
 {
  SQLInfo info = (SQLInfo) channel.take();   

  if(info==null)
  {
   ontinue;
  }
  for (int i = 0, n = dbListeners.length; i < n; i++)
  {
   dbListeners[i].logSql(info);
  }

 }


在调用channel.take()以后,这个SQLInfo就从channel中去除了。这时如果DBLogger的方法被调用,那么即使dbListeners[i].logSql(info)仍然在运行,但是DBLogger会认为channel已经空了,所有的dbListeners都可以被close了,而在DataBaseDBListener的close方法中会把输出目标数据库connection关掉,那么此时如果DataBaseDBListener的logSql方法还在调用的话,那么一旦使用这个connection,那么就会出现错误了。

原文转自:http://www.ltesting.net