如鹏网 大学生计算机学习社区

CowNew开源团队

http://www.cownew.com 邮件请联系 about521 at 163.com

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  363 随笔 :: 2 文章 :: 808 评论 :: 0 Trackbacks

#

CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息

我准备给JDBMonitor增加一个性能监测报表的功能。用户在“报表条件”中填写要统计的起始时间、结束时间和单位时间后,点击查询。程序从DataBaseDBListener记录的表T_LOG_SQLLog中进行统计并显示报表。例如:用户在起始时间中输入”2006-5-30 18:00:00”,结束时间输入”2006-6-1 12:00:00”,时间单位选择“5分钟”,点击“查询”。程序将把T_LOG_SQLLog中FbeginTime大于等于”2006-5-30 18:00:00”,小于等于”2006-6-1 12:00:00”的记录过滤出来。然后统计每5分钟记录的条数(也就是数据库执行的次数),以时间序列图的形式显示成报表。
比如:
fid       ftime
1 2006-05-05 10:00:00.000
2 2006-05-05 10:00:01.000
3 2006-05-05 10:00:10.000
4 2006-05-05 10:01:10.000
5 2006-05-05 10:01:20.000

这样的数据属于离散的数据,因为数据库的执行时间是不确定的,要把它们按统计它们的出现次数常常需要使用数据挖掘的东西。数据挖掘通常都是不同的数据库有不同的实现的,JDBMonitor是跨数据库的,因此肯定不能使用这些数据库特有的东西。现在也有一些开源的跨数据库的数据挖掘引擎,但是其尺寸巨大无比,都要50M以上。JDBMonitor是一个小的工具,为了方便部署和使用,JDBMontior的一个基本原则就是尽量避免使用JDK之外的类,所以肯定不能使用它们。我经过仔细思考,发现可以通过如下技巧来解决:

select count(sub.f) as exeCount,min(sub.FBeginTime) as FTime from(
select cast(DateDiff(ss,?,FBeginTime)/? as int) as f,FBeginTime from T_LOG_SQLLog
)as sub
where 1=1
and FBeginTime>=?
and FBeginTime<=?
group by sub.f
order by sub.f ASC


其中第一、三个参数传递用户选择的时间段的起始时间,第二个参数是用户选择的计时间隔(以秒为单位),参数四是用户选择的时间段的结束时间。
我采用的是整除的技巧来实现的这个效果。
其中FBeginTime是SQL语句执行的开始时间(在这里我们就把它看作SQL语句的执行时间),cast(DateDiff(ss,?,FBeginTime)/? as int) as f的意思就是计算SQL语句的执行时间到选择的时间段的起始时间之间的秒间隔数,然后再整除用户选择的计时间隔(以秒为单位)。经过整除以后同一个时间段内的数据就相同了,然后我们一个groupby,然后一个count(sub.f),这样各个时间段sql的执行次数就出来了。
以上边的数据为例,假如我输入的起始时间是2006-05-05 10:00:00.000,结束时间是2006-05-05 10:02:00.000。
那么select cast(DateDiff(ss,?,FBeginTime)/? as int) as f,FBeginTime from T_LOG_SQLLog的结果集就是:
f  FBeginTime
0 2006-05-05 10:00:00.000 
0 2006-05-05 10:00:01.000 
0 2006-05-05 10:00:10.000
1 2006-05-05 10:01:00.000
1 2006-05-05 10:01:00.000 
然后,以f为分组条件进行汇总,并统计f的count,这样各个时间段sql的执行次数就出来了:
3 2006-05-05 10:00:00.000 
2 2006-05-05 10:01:00.000 
当然不同的数据库的计算日期时间差和截取整数的方式是略有差异的,我这里用的是mssqlserver的语法。

posted @ 2006-06-12 01:30 CowNew开源团队 阅读(1079) | 评论 (0)编辑 收藏

我上上个月申请java.net的开源服务,没想到前两天才收到抄送给我的邮件,收件人是java.net的另外一个工作人员,发件人要收件人,批准我的请求:
发件人:"Eric Renaud"
收件人:leads@javatools.dev.java.net
抄送:cownew@dev.java.net
主题:New Java.net Request to JavaTools - jdbmonitor

To: JavaTools Community Leaders -

https://jdbmonitor.dev.java.net/

This project has been moved to your inbox for review.
Please approve or disapprove ASAP.
......
工作效率太慢了,我回邮件道:

The working efficiency too lowered!
My request to sourceforge already approved last month,I don't need your webhosting service anymore,thanks  all the same!
没想到今天竟然收到一封中文邮件:

对不起,你要主办项目jdbmonitor的请求你被否决。你再也不能为项目jdbmonitor访问任何资源。
以下是否决的理由:
Project
owner moved to sourceforge, so, he does not want to host it at java.net
anymore.
关于更多信息,请联系fabiane (@dev.java.net)”
呵呵,原来不光中国人办事效率低呀。
posted @ 2006-06-10 22:47 CowNew开源团队 阅读(262) | 评论 (0)编辑 收藏

CowNew开源团队网站 http://www.cownew.com
论坛    http://www.cownew.com/newpeng/
转载请注明此版权信息。

ORM在整个java社区使用越来越广泛,但是随着更多的项目使用ORM,很多人也感到了它的不足:慢,甚至慢的让人无法忍受!可是让我们从ORM的原理仔细思考一下,就会发现,使用ORM并不会明显降低运行速度。因为无论什么ORM工具都是根据对象去动态构造SQL语句,执行的,相信无论构造SQL的速度多么慢,那和数据库操作比起来,几乎是可以忽略不计的。但是为什么确实又那么慢呢?归根结底,是对ORM的使用不当造成的。
1、陋习:过渡依赖ORM的Update和delete。比如,将某个人的年龄加3,很多人就会如下写:
PersonInfo p = orm.getPerson(...);
p.setAge(p.getAge);
orm.update(p);
看看,这一来一回就要两个sql语句,先取数据:select age,id,.... from T_Person,然后再update,update T_Person set age=23....。
相信没有ORM,谁也不会去这么写。直接写sql:update T_Person set age=age+3 where...这不很好吗?速度不会快多了吗?
又如:删除年龄为15的人,有的人就敢这么写:
PersonInfo persons[] = orm.getPersons("age=15");
for(int i=0,n=persons.length;i<n;i++)
{
   orm.delete(persons[i]);
}

我真的要疯了,它真的不懂delete from T_person where age=15吗??
根据我个人的经验如果要发挥ORM的最大作用,同时最大程度的避免其副作用,我建议最好只使用orm的addNew(增加数据)和get***Info(从数据库中取数据)的功能,而对update,delete则直接写sql,这样最好。
ORM+JDBC,优美和效率的最佳结合点。
2、认为ORM万能。在写一些报表的时候甚至也有人用orm取出数据,然后通过代码来出报表。相信稍微复杂一点的报表就能把人搞死。所以报表,千万不能用ORM,直接写SQL是最好的事情。

posted @ 2006-06-09 01:33 CowNew开源团队 阅读(852) | 评论 (0)编辑 收藏

CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息
       
        昨天发现JDBMonitor在多数据源的情况下会有问题,这个问题就是对单例模式理解不深造成的。为了减少系统中的对象数目,我用单例模式设计DBLogger,也就是提供一个getLogger方法返回一个日志处理器,getLogger则返回的是一个缓存了的DBLogger实例。昨天我用一个大型的信息系统测试了一下,发现当有多个数据源存在的时候,所有的日志都记录到了第一个启动的JDBMonitor的配置文件指定的监听器中了。经过分析得知,虽然多个数据源启动了多个JDBMonitor,但是由于这些JDBMonitor实例是运行在同一个JVM中的,而一个类变量在同一个JVM是唯一的,所以这些实例调用getLogger的时候得到的都是第一个JDBMonitor中配置的了。
        我采用如下方式解决:为getLogger增加一个connectionId参数,将原先的单例去掉,改成一个hash表的静态变量instanceMap。在调用getLogger的时候,先以connectionId为key到instanceMap中找是不是已经有一个实例了,如果有则直接返回这个实例,否则构造一个DBLogger,将此DBLogger以connectionId为key保存到instanceMap中,然后返回实例。
        根据JDBMonitor的功能特点配置文件的路径就可以做为这个connectionId了,也就是如果是多个数据源指向一个配置文件,那么这几个数据源其实还是共用一个DBLogger,这个也是合理的,而且也可以节省很多资源。
        从这个例子我们可以看出,单例模式并不一定是只创建一个实例这么简单。Log4j的getLogger就是很好的证明。
        但是多个数据源共用一个DBLogger又引来了另一个问题,就是当有一个数据源的Connection被close掉以后,DBLogger也会随之close掉,其他数据源再访问的时候就会报错。我采用类似GC、COM等的引用机制解决此问题。在DBLogger内部维护一个计数器refCounter,初始值是0,当调用getLogger访问到此实例的时候,就refCounter自动加1,当调用DBLogger的close的时候就自动减1,当refCounter降到0的时候就说明没有对象引用到它了,这个时候再释放DBLogger中的各种资源。当然addRef、releaseRef、close等方法都要标识成synchronized的。
        同理,以前的这些channel、dbListeners类变量也要改成实例变量。consumerthread也要改成实例变量,在close中再关闭这个线程。这样就保证了每一个JDBMonitor都有自己的消费者线程。
        为了使语意更加明确,我将getLogger重命名为createLogger。
        代码已经提交到CVS,今天晚些时候将打包放到团队网站上。
        向大家汇报,SQL解析引擎已经有阶段成果,强类型AST节点都已定义完毕,也已经可以生成最简单的CommonAST。

 

posted @ 2006-06-06 20:55 CowNew开源团队 阅读(900) | 评论 (0)编辑 收藏

    为了测试我的一个业务系统在不同数据库上的表现,我的tomcat上配置了多个数据源,这样我可以轻松的切换系统到不同的数据源上。为了监测每个数据源的运行状况,随时观测执行的sql语句,我为每个数据源都配置了JDBMonitor,并且这些数据源的JDBMonitor的配置文件共用一个config.xml文件。

    但是在我运行的时候却发现系统报错“java.net.bindexception:  address  in  use:  jvm_bind”,根据我三十多年的从医经验判断,俺认为是端口冲突。。。。。。唉,别扔臭鸡蛋呀,呵呵。原来是我在config.xml中配置了SocketDBListener,端口为默认的9527,这样当第一个数据源使用以后,这个数据源将启动一个SocketDBListener,所以9527端口就被占用了,以后其他的数据源被时候以后在启动SocketDBListener的时候,也尝试去监听9527端口,这样就出现了如上面的错误。解决问题很简单:为每个数据源都指定一个不同的配置文件(比如config1.xml,config2.xml),并且在每个配置文件中都配置不同的端口(比如9527、9528、3721、9981等等,只要不互相重复,并且不与系统中其他软件占用的端口冲突即可)。
  
   JDBMonitor今天修改了一个在一个JVM中启动多个JDBMonitor的bug。已经提交到CVS,并更新网站下载。
posted @ 2006-06-06 01:49 CowNew开源团队 阅读(510) | 评论 (0)编辑 收藏

作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息

我们经常需要将我们的程序运行中的一些信息(比如在选项对话框中的设置)记录下来,以做便再次运行的时候不用再重写填写这些数据。这对改善软件的人机可用性方面是很有用的。但是让人失望的是,现在很多Java开源软件在这一点做的很不好,每次运行都要用户去填写那些配置文件。做为最好用的数据库监控、日志工具,JDBMonitor在这方面做的是非常好的,以它的Swing界面监视器和数据库日志记录查询窗口中所有的配置信息(例如远程服务器地址、端口、数据库名称、JDBC驱动等等)都是被保存的,当再次运行的时候程序会自动加载这些配置信息,所以使用起来相当方便。
我们接下来就来分析一下JDBMonitor是如何实现的。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
保存加载配置文件有多种方式,比如xml文件、properties文件等,采用这些保存方式的一个问题就是如果程序是以jar,war 包等方式发布的那么这些配置文件就不能放在包中,因为包中的文件是不能在运行时改动的,只能放在磁盘的文件中,但是放在磁盘的文件中又很容易出现因为操作系统的差异、权限等问题造成程序的问题。JDBMonitor采用的则是JDK中的Preferences类来避免这些问题。
JDK1.4中提供了Preferences类,在java.util.prefs包里面。Preferences类在不同的平台中有不同的实现方式。比如在Windows平台中,Preferences是将数据保存在注册表中的。

为了区分不同的应用程序的参数项,在建立Preferences时要指定一个节点路径。
Preferences是一个抽象类,提供了一系列静态方法和抽象方法来操作参数项:
 Preferences userData = Preferences.userNodeForPackage(this); //得到用户配置节点
 Preferences sysData = Preferences.systemNodeForPackage(this); //得到系统配置节点。
比如在windows中Preferences.userNodeForPackage代表得到 HKEY_CURRENT_USER\Software\JavaSoft\Prefs下的相对路径
Preferences.systemNodeForPackage代表得到  HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs下的相对路径

Preferences的读取、存储是非常容易的,存储只要调用put***方法就可以,读取调用get***即可,不同的put,get方法分别用于存取不同的数据类型,详细信息可以参考JavaDoc。
以JDBMonitor的Swing界面监视器的连接对话框为例为大家分析,打开com.cownew.JDBMonitor.listenerImpl.sckListenerClient.ConnectConfigDialog,saveConfig()和loadConfig()分别就是保存和读取参数用了,这两个方法会在超类中被调用。可以看到代码实现非常简单:
protected void saveConfig()
 {
  Preferences prefer = Preferences.userNodeForPackage(getClass());
  prefer.put(HOST_NAME,getHostName());
  prefer.putInt(PORT,getPort());
 }
 
 protected void loadConfig()
 {
  Preferences prefer = Preferences.userNodeForPackage(getClass());
  setHostName(prefer.get(HOST_NAME,""));
  setPort(prefer.getInt(PORT,9527));
 }

posted @ 2006-06-02 23:48 CowNew开源团队 阅读(961) | 评论 (0)编辑 收藏

作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息

数据库监控、日志工具JDBMonitor在介绍文档中说到“JDBMonitor另起一个线程来记录SQL,所以它不会对程序运行速度有任何影响。”,那么它是如何做到的呢?
JDBMonitor采用“生产者-消费者模型”完成此功能。学过操作系统原理的朋友对“生产者-消费者模型”一定不陌生,它是和“哲学家进餐问题”等相提并论的经典模型。
JDBMonitor的主线程做为“生产者”,产生“日志信息”这个产品,另起一个线程做为消费者,这个消费者负责“消费”日志信息,并把日志信息派发给所有的监听者,这样日志的产生和消费是独立的,所以无论日志的派发有多慢,都没有关系,都不会影响到主线程的运行速度。下面让我们深入研究一下:
(注:JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。)
打开com.cownew.JDBMonitor.common.DBLogger。JDBMonitor每次截获到一条sql语句,都会调用logSQL方法,并把sql语句的信息对象传过来,这样我们就可以把logSQL方法当成生产者,logsql把消息放到channel中。LogConsumer是一个实现了Runnable接口的类,它就是日志的消费者,并且是运行于另一个线程的,它负责实时检测channel,只要channel中有东西,他就从channel取出日志对象,然后发送给各个监听器。
startConsumer中
for (;;)
{
  SQLInfo info = (SQLInfo) channel.take();
  for (int i = 0, n = dbListeners.length; i < n; i++)
  {
    dbListeners[i].logSql(info);
  }
}
就是在实时检测channel中的产品。
channel是一个阻塞通道BlockedChannel的实例,这个阻塞通道主要提供两个方法offer,take,offer方法向通道中放入产品,take从通道中取产品,当通道中没有产品的时候,take方法将会阻塞,直到有产品为止。BlockedChannel是靠java的wait-notify机制实现的,原理非常简单,有兴趣的朋友看一下其实现代码就可以。
值得注意的是,LogConsumer是一个后台线程,因为如果LogConsumer不是后台线程,那么由于LogConsumer一直在无限循环里执行,所以程序就不能正常终止。而设置为后台线程后,在其他工作线程停止后,此线程就会自动终止。关于“后台线程”的知识,可以查看相关资料。
但是采用后台线程以后,又有另一个问题出现了,在主线程停止后,有可能产品通道channel中还有没有发送完的日志信息,这样就会造成漏记日志信息。
Runtime 类有一个addShutDownHook方法,可以调用此方法向JVM注册一个监听器,这个监听器必须实现Thread接口,在JVM停止之前,这个监听器将会被运行,这样我们就可以在JVM停止之前做一些事情了。
JDBMonitor就是用addShutDownHook解决此问题的。见DBLogger的静态初始化块:

Runtime.getRuntime().addShutdownHook(new Thread(){
  public void run()
  {
    //once JVM will shutDown,this hook will pause the shutingdown
    //until all the SQLInfo be dispatched
    while (!channel.isEmpty())
    {
      try
      {
        Thread.sleep(SHUTDOWNSLEEPMSECOND);
      } catch (Exception e)
      {
        throw CommonUtils.toRuntimeException(e);
      }
    }
    ...
   }
}); 

在JVM停止之前会首先检测产品通道中有没有产品,如果还有,则会一直等到产品被消费完后再终止。

 while (!channel.isEmpty())
    {
      try
      {
        Thread.sleep(SHUTDOWNSLEEPMSECOND);
      } catch (Exception e)
      {
        throw CommonUtils.toRuntimeException(e);
      }
    }

posted @ 2006-06-02 23:46 CowNew开源团队 阅读(940) | 评论 (0)编辑 收藏

作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息

  有一定开发经验的朋友在处理异常的时候都不会直接写个e.printstacktrace()来“捕获”异常,但是在有些情况下是“无法抛出”异常的,比如一些重载基类的一些方法,但是这些方法是没有声明异常抛出的,或者在类的static初始化块的时候也是“无法抛出”异常的。其实“无法抛出异常”的地方还是能抛出运行时异常的。
最好用的数据库监控、日志工具JDBMonitor就是通过这种方式解决此问题的。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
JDBMonitor在CommonUtils总定义了一个toRuntimeException方法,用来把异常转换成运行时异常:
public static RuntimeException toRuntimeException(Throwable e)
{
 RuntimeException re = new RuntimeException(e);
 re.setStackTrace(e.getStackTrace());
 return re;
}
让我们首先打开com.cownew.JDBMonitor.jdbc.DBDriver,然后定位到代码的最后
static
{
    try
    {
 DriverManager.registerDriver(new DBDriver());
    } catch (Exception e)
    {
 throw CommonUtils.toRuntimeException(e);
    }
}
这是在类的初始化块中向DriverManager注册JDBC驱动,在初始化块中是不能声明抛出异常的,因此JDBMonitor将异常转化为RuntimeException异常抛出。这样就做到了不放过任何一个异常。

再打开:
com.cownew.JDBMonitor.listenerImpl.sckListenerClient.ListenerClient.java中的SocketListener类,其中的run方法是实现的Runnable接口中的方法,而Runnable接口中的Run方法是没有声明异常的,因此JDBMonitor也是采用的转换成RuntimeException的方式进行的异常处理:
public void run()
{
  try
  {
 ...
  } catch (IOException e)
  {
    throw CommonUtils.toRuntimeException(e);
  } catch (ClassNotFoundException e)
  {
    throw CommonUtils.toRuntimeException(e);
  }
}

posted @ 2006-06-02 23:46 CowNew开源团队 阅读(813) | 评论 (0)编辑 收藏

作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息

正则表达式是一个非常强大的工具,有了这个工具,在进行字符串的解析、修改等不会再麻烦,比写一堆if else语句更清晰易懂。
关于正则表达式的基础知识我这里不再多讲,大家可以到网上查找相关的资料。本文假定您已经熟悉正则表达式的基本使用。
让我们以最好用的数据库监控、日志工具JDBMonitor为例来讲解。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
DataBaseDBListener要读取形如"dburl=jdbc:odbc:MQIS;user=sa;password=sa;logtable=T_Log_Log"的配置字符串,然后从中解析数据库连接配置、表名等信息,并且user=sa;password和logtable部分也是可以忽略的(这是当然的,因为有的数据库不需要用户名密码,而且logtable也有默认值)。
打开com.cownew.JDBMonitor.listenerImpl.DataBaseDBListener,init就是进行参数arg的解析的:
1、Pattern patAll = Pattern.compile("dburl=(.+?);?(user=.*;password=.*;)?(logtable=.+)?");
这句是从arg中提取三个部分,分别是dburl部分,用户名密码部分,logtable部分。因为用户名密码部分,logtable部分是可以忽略的,因此采用"?"来标识这个两个分组“(user=.*;password=.*;)?”、“(logtable=.+)?”。而一旦dburl部分,用户名密码部分忽略,那么dburl=...后的;也是可以忽略的,因此";?"。
值得我们注意的是“dburl=(.+?)”,为什么不是"dburl=(.+)"呢?怎么多了个?。你可以尝试去掉“?”后,再次运行。你会看到dburl=后所有的字符,包括用户名密码部分,logtable部分都被看成dburl=的值了,也就是后边的字符都被吃掉了。为什么呢?
这就要提到正则表达式的贪婪性和懒惰性,关于贪婪性和懒惰性可以查看网上一篇文章《深入浅出之正则表达式》(http://dragon.cnblogs.com/archive/2006/05/08/394078.html)。
象《深入浅出之正则表达式》描述的那样:“+”是贪婪的。也就是说,“+”会导致正则表达式引擎试图尽可能的重复前导字符。只有当这种重复会引起整个正则表达式匹配失败的情况下,引擎会进行回溯。也就是说,它会放弃最后一次的“重复”,然后处理正则表达式余下的部分。一个用于修正以上问题的可能方案是用“+”的惰性代替贪婪性。你可以在“+”后面紧跟一个问号“?”来达到这一点。“*”,“{}”和“?”表示的重复也可以用这个方案。
因此JDBMonitor就采用了dburl=(.+?)来解决这个贪婪性问题。
2、Pattern patUserPwd = Pattern.compile("user=(.*);password=(.*);");
在第一步中把“user=sa;password=sa;”当成一个整体来提取,那么我们接下来还要从这个提取中的串中提取用户名user、密码password信息。因此采用这种方式来提取。这种分步提取的方式比写复杂的正则表达式一次性提取看起来更清晰,更加易维护。

posted @ 2006-06-02 23:43 CowNew开源团队 阅读(909) | 评论 (0)编辑 收藏

作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
CowNew开源团队网站 http://www.cownew.com
论坛 http://www.cownew.com/newpeng/
转载请注明此版权信息

我个人是极力反对不必要的downcasting的,但是在使用java的集合类的时候确是不可避免的,因为JDK5之前的集合中只能存储Object类型,所以看到一个List的时候,你也不知道里边放的是什么数据类型,只能胆战心惊的来下转型:Integer i = (Integer)list.get(i)。
好在JDK5可以使用泛型了,这个问题也就迎刃而解了。这样就再也不会去去问其他开发人员“你List里放的是什么类型的对象?”,再也不会望着一大堆以“老祖先”形式表现的object了发呆了,终于可以看到容器中存的这些对象的类型了。
但是在有的情况下我们还是不能使用JDK5的,比如你的正在开发的系统是基于JDK1.4的,那么迁移到JDK5是有一定风险的,或者你开发的模块要被JDK5一下的程序使用的,那么就暂时放弃JDK5的这个新特性了。
那么没有泛型我们就没法解决这个问题了吗?非也!鸟枪!呵呵。
一种方式是自己包装一下List写一个自己的专有数据类型的List,比如
class IntegerList()
{
   private List list;
   ......
   public void add(Integer i)
   {
     list.add(i);
   }
   public Integer get(int i)
   {
      return (Integer)list.get(i);
   }
}
这样做的缺点就是对每个数据类型都要生成一个集合类,无疑加大了代码量。
另一种方式就是使用数组解决此问题,因为数组中的数据类型是清晰的,比如Integer[] ia = new Integer[5];,一眼就可以看出其中存储的是什么类型。
最好用的数据库监控、日志工具JDBMonitor就是通过这种方式解决此问题的。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
打开com.cownew.JDBMonitor.jdbc.connect
定位到:
List lisList = configInfo.getListenerInfoList();
DBListenerInfo[] dbListenerInfos = new DBListenerInfo[lisList.size()];
for(int i=0,n=lisList.size();i<n;i++)
{
    DBListenerInfo lisInfo = (DBListenerInfo) lisList.get(i);
    dbListenerInfos[i] = lisInfo;
}    
return new DBConnection(cn,dbListenerInfos);  
程序把多个监听器对象信息DBListenerInfo拼转成DBListenerInfo数组,然后传递给DBConnection。
DBConnection接收到dbListenerInfos会把它转发给DBLogger做为其构造函数的参数:
private DBLogger(DBListenerInfo[] dbListenerInfos)
这样在DBLogger内部就可以很清晰的知道dbListenerInfos中的数据类型了:
for(int i=0,n=dbListenerInfos.length;i<n;i++)
{
   ...
   DBListenerInfo info = dbListenerInfos[i];
   ...
}

在系统的接口边界处传递的数据类型非常明确,不会因为传递一个光秃秃的List而不知道其类型,然后胆战心惊的进行类型转换了。
因此我认为在一个方法或者类的内部可以采用List等进行数据的处理,但是当需要与外部(相对于类来说就是其他类,相对于方法来说就是其他方法)交换多个同构对象的时候,最好转换成数组传递,这样就清晰多了。

posted @ 2006-06-02 23:41 CowNew开源团队 阅读(744) | 评论 (0)编辑 收藏

仅列出标题
共30页: First 上一页 20 21 22 23 24 25 26 27 28 下一页 Last