星期五, 五月 25, 2007

去除list中的重复元素

用HashSet
 
Iterator it =list.iterator();
HashSet set = new HashSet();

while(it.hasNext()){
set.add(it.next());
}
it = set.iterator();
list.clear();
while(it.hasNext()){
list.add(it.next());
}

或者是
 
list = new ArrayList(new HashSet(oldList));
 

星期四, 五月 24, 2007

java 读 properties格式文件


package hddqcs.datamining.venus.venusfile;

import hddqcs.datamining.venus.common.DMLogger;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.log4j.Logger;

/**
 *
 * COPYRIGHT(C) Hitachi Global Storage Technologies, Inc.
 * All Rights Reserved.
 *
 * This Class is to reading the process config file
 *
 *  eg. etl_venusProcess.properties
 *
 * @author liuqact
 */
public class ReadingProcessProsFile {
 Logger logger = Logger.getLogger(ReadingProcessProsFile.class.getName());
 public Properties getProperties(String dir,String fileName)throws FileNotFoundException,IOException,Exception {
  // TODO Auto-generated method stub
  try{
   Properties pros = new Properties();
   InputStream prosFile = new FileInputStream("Log4j.properties");
   pros.load(prosFile);
  return pros;
  }catch(FileNotFoundException e){
   logger.error("Properties file inputted is not exist");
   throw e;
  }catch(IOException e){
   logger.error("Reading Properties file inputted failed");
   throw e;
  }catch(Exception e){
   logger.error("get values from Properties file inputted failed");
   throw e;
  }
 }
}

关于serialVersionUID


在定义一个实现接口java.io.Serializable 的类时
如果用EC IDE 会有缺少 UID的警告
 
加一个吧,可以减少程序运行时的资源消耗
 
在EC中,假如类出现这样的警告,那么你可以把鼠标放到类名上,然后
CTRL+1
看看出现在什么
中间有一个是生成serialVersionUID的
 

星期三, 五月 23, 2007

Java操作Excel的一些可以参考的资源

http://sourceforge.net/projects/jexcelapi
JExcelApi is a java library which provides the ability to read, write, and modify
Microsoft Excel spreadsheets. This project mirrors the files on http://www.jexcelapi.org,
which has been known to go down on occasion.

 http://sourceforge.net/projects/excelutils
ExcelUtils, easy export report in excel by excelutils.It like velocity or freemarker, but
it's script is written in excel to control excel format and data.

http://sourceforge.net/projects/exceltemplate
Templating system for Microsoft Excel files in Java.
 
http://sourceforge.net/projects/jaoff
JavaOffice is a pure Java library to read and write MS Word files in the new WordML (format) and
MS Excel files in the new SpreadsheetML format. WordML and SpreadsheetML are xml formats for word
and excel files supported from Office 2003 and above.
 
Simple library written in Java to allow the creation of Excel files based on a Java Collection.
Each element of the collection goes in a row and the columns are based on the properties you define
through an XML config file.
 
http://sourceforge.net/projects/caxton
Caxton is a general purpose package written in Java that is used to render HTML, PDF (using FOP),
 RTF (using JFOR), and Excel (using POI) using stylesheets. There are some additional tools for
 providing easy access to XML, merging XSL stylesheets

Eclipse插件-- Bytecode Outline,Implementors, FindBugs 等

1. Eclipse插件之Bytecode Outline

本文介绍如何利用Eclipse插件Bytecode Outline在Eclipse中的操作使用。

  Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

  Bytecode Outline 插件可以把当前的正在编辑Java的文件或者class文件直接显示出其相应的字节码出来,而且可以进行两个Java文件的字节码比较或者两个class文件的字节码比较或一个Java文件与一个class文件进行字节码的比较。
 

原文出处: http://dev2dev.bea.com.cn/bbsdoc/20060123182.html

2 Eclipse插件之Implementors

本文介绍如何利用Eclipse插件Implementors在Eclipse中的使用。

  Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

问题提出:
  如果你想看看某个类或者方法的实现,一般是Ctrl + 鼠标左键,单击即可以打开这个类或者方法的具体实现代码。但是如果碰到接口时,只是到达接口而已,不能到达具体的实现类里。

解决方法:利用Eclipse的Implementors插件。
  当追踪方法代码时,Eclipse默认是转到方法的接口类,而接口中是只有方法名称没有具体的实现代码,此插件提供了追踪到具体实现类的实现代码的功能。

  另外还有Call Hierarchy插件: 显示一个方法的调用层次,可以从中看到它被哪些方法调用了,以及它调用了哪些方法,是代码追踪比较实用的工具。Eclipse 3.1中已经自带有这个功能了。这个插件就不用另加介绍了。

详细信息参考: http://dev2dev.bea.com.cn/bbsdoc/20060124188.html 

3 利用Eclipse开发Hibernate应用程序 --Hibernate Synchronizer插件

介绍如何利用Hibernate Synchronizer插件在Eclipse 3.0.1中快速的开发Hibernate应用程序,提高我们的工作效率。
本文介绍如何利用Eclipse插件EasyExplorer在Eclipse中的使用。

  Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境,Hibernate也是目前很流行的O/R Mapping框架,至少在EJB 3.0大行其道之前,它是我们在考虑O/R Mapping时非常好的选择。

  关于Hibernate框架的细节,请参考《Hibernate in Action》一书。

详细内容点击这里: http://dev2dev.bea.com.cn/bbsdoc/20060124187.html

4 Eclipse插件之EasyExplorer

  Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

问题提出:
  如果你经常需要在Eclipse里打开相关资源文件所在的文件夹,比较麻烦,要右键,属性,在Location一栏中把所在的文件夹拷贝一下,然后再去资源管理器里输入这个路径,回车,打开它。

解决方法:
  用EasyExplorer插件,有了这个插件就可以很方便地打开资源文件所在的文件夹了。
 

详细内容点击这里 ; http://dev2dev.bea.com.cn/bbsdoc/20060124184.html 

5 Eclipse插件之SQLExplorer

本文介绍如何利用Eclipse插件SQLExplorer在Eclipse中连接各种数据库进行操作使用。

  Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。
 

详细内容点击这里 http://dev2dev.bea.com.cn/bbsdoc/20060126189.html 

6 Eclipse插件之FindBugs

本文介绍如何利用Eclipse插件FindBugs在Eclipse中的使用。

  Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

问题提出:
  当我们编写完代码,做完单元测试等各种测试后就提交正式运行,只能由运行的系统来检测我们代码是否有问题了,代码中隐藏的错误在系统运行的过程中被发现后,然后再来进行相应的修改,那么后期修改的代价就相当高了。

解决方法:
  现在有很多Java代码分析工具,FindBugs中开源项目当中的一个,它可以帮你找到代码中隐藏的一些错误,提升你的代码能力与系统安全可靠性。
 
FindBugs:0.9.4 从http://findbugs.sourceforge.net/
官方的文档 http://findbugs.sourceforge.net/manual/
Eclipse plugin for FindBugs version 0.0.17
http://findbugs.sourceforge.net/downloads.html 下载

详细内容点击这里: http://dev2dev.bea.com.cn/bbsdoc/20060124186.html

星期二, 五月 22, 2007

JDK1.5中的线程池使用简介(转)


在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。这里介绍的就是1.5种的线程池的简单使用方法。
创建日期:2005-05-11
最后修改日期:2007-03-06
panhaidong@gmail.com

一、简介
线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
  • corePoolSize
    线程池维护线程的最少数量
  • maximumPoolSiz
    线程池维护线程的最大数量
  • keepAliveTime
    线程池维护线程所允许的空闲时间
  • unit
    线程池维护线程所允许的空闲时间的单位
  • workQueue
    线程池所使用的缓冲队列
  • handler
    线程池对拒绝任务的处理策略

一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

当一个任务通过execute(Runnable)方法欲添加到线程池时:

  • 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
  • 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
  • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
  • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
也就是:处理任务的优先级为:
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue

handler有四个选择:
  • ThreadPoolExecutor.AbortPolicy()
    抛出java.util.concurrent.RejectedExecutionException异常
  • ThreadPoolExecutor.CallerRunsPolicy()
    重试添加当前的任务,他会自动重复调用execute()方法
  • ThreadPoolExecutor.DiscardOldestPolicy()
    抛弃旧的任务
  • ThreadPoolExecutor.DiscardPolicy()
    抛弃当前的任务

二、一般用法举例 [下载源代码]

package cn.simplelife.exercise;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {
private static int produceTaskSleepTime = 2;
public static void main(String[] args) {
//构造一个线程池
ThreadPoolExecutor producerPool = new ThreadPoolExecutor(2, 4, 0,
TimeUnit.SECONDS , new ArrayBlockingQueue(3),
new ThreadPoolExecutor.DiscardOldestPolicy());

//每隔produceTaskSleepTime的时间向线程池派送一个任务。
int i=1;
while(true){
try {
Thread.sleep(produceTaskSleepTime);

String task = "task@ " + i;
System.out.println("put " + task);

producerPool.execute(new ThreadPoolTask(task));

i++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

package cn.simplelife.exercise;

import java.io.Serializable;

/**
* 线程池执行的任务
* @author hdpan
*/
public class ThreadPoolTask implements Runnable,Serializable{

//JDK1.5中,每个实现Serializable接口的类都推荐声明这样的一个ID
private static final long serialVersionUID = 0;

private static int consumeTaskSleepTime = 2000;
private Object threadPoolTaskData;

ThreadPoolTask(Object tasks){
this.threadPoolTaskData = tasks;
}

//每个任务的执行过程,现在是什么都没做,除了print和sleep,:)
public void run(){
System.out.println("start .."+threadPoolTaskData);
try {
//便于观察现象,等待一段时间
Thread.sleep(consumeTaskSleepTime);
} catch (Exception e) {
e.printStackTrace();
}
threadPoolTaskData = null;
}
}


对这两段程序的说明:

  1. 在这段程序中,一个任务就是一个Runnable类型的对象,也就是一个ThreadPoolTask类型的对象。
  2. 一般来说任务除了处理方式外,还需要处理的数据,处理的数据通过构造方法传给任务。
  3. 在这段程序中,main()方法相当于一个残忍的领导,他派发出许多任务,丢给一个叫 threadPool的任劳任怨的小组来做。
    • 这个小组里面队员至少有两个,如果他们两个忙不过来, 任务就被放到任务列表里面。
    • 如果积压的任务过多,多到任务列表都装不下(超过3个)的时候,就雇佣新的队员来帮忙。但是基于成本的考虑,不能雇佣太多的队员, 至多只能雇佣 4个。
    • 如果四个队员都在忙时,再有新的任务, 这个小组就处理不了了,任务就会被通过一种策略来处理,我们的处理方式是不停的派发, 直到接受这个任务为止(更残忍!呵呵)。
    • 因为队员工作是需要成本的,如果工作很闲,闲到 3SECONDS都没有新的任务了,那么有的队员就会被解雇了,但是,为了小组的正常运转,即使工作再闲,小组的队员也不能少于两个。
    • 通过调整 produceTaskSleepTime和 consumeTaskSleepTime的大小来实现对派发任务和处理任务的速度的控制, 改变这两个值就可以观察不同速率下程序的工作情况。
    • 通过调整4中所指的数据,再加上调整任务丢弃策略, 换上其他三种策略,就可以看出不同策略下的不同处理方式。
    • 对于其他的使用方法,参看jdk的帮助,很容易理解和使用。
    这是另外一个例子
    public class NamePrinter implements Runnable {
    private final String name;
    private final int delay;
    public NamePrinter(String name, int delay) {
    this.name = name;
    this.delay = delay;
    }
    public void run() {
    System.out.println("Starting: " + name);
    try {
    Thread.sleep(delay);
    } catch (InterruptedException ignored) { }
    System.out.println("Done with: " + name);
    }
    }
    import java.util.concurrent.*;
    import java.util.Random;
    public class UsePool {
    public static void main(String args[]) {
    Random random = new Random();
    ExecutorService executor =
    Executors.newFixedThreadPool(3); //设定线程池容量为3
    // Sum up wait times to know when to shutdown
    int waitTime = 500;
    for (int i=0; i<10;>
    String name = "NamePrinter " + i;
    int time = random.nextInt(1000);
    waitTime += time;
    Runnable runner = new NamePrinter(name, time);
    System.out.println("Adding: " + name + " / " + time);
    executor.execute(runner);
    }
    try {
    Thread.sleep(waitTime);
    executor.shutdown();
    executor.awaitTermination
    (waitTime, TimeUnit.MILLISECONDS);
    } catch (InterruptedException ignored) {
    }
    System.exit(0);
    }
    }

    附:jdk1.5中关于ThreadPoolExecutor的javadoc地址

    星期日, 五月 20, 2007

    星期五, 五月 18, 2007

    Java SE 6中JDBC 4.0的增强特性(转)

    摘要:

    Java SE 6包含了对Java数据库互连(JDBC)API的一些增强特性。这些增强特性的版本将定为JDBC version 4.0。JDBC新特性的目的是提供更简单的设计和更好的开发体验。本文将概述JDBC 4.0的增强特性和为企业级Java开发人员带来的好处。我们将通过一个用Apache Derby作为后台数据库的贷款处理应用范例来探究JDBC的新特性。

    Java SE 6包含了对Java数据库互连(JDBC)API的一些增强特性。这些增强特性的版本将定为JDBC version 4.0。JDBC新特性的目的是提供更简单的设计和更好的开发体验。本文将概述JDBC 4.0的增强特性和为企业级Java开发人员带来的好处。我们将通过一个用Apache Derby作为后台数据库的贷款处理应用范例来探究JDBC的新特性。

    Java SE 6.0
    Java SE 6.0版以兼容性、稳定性和品质作为设计目标。本版本中有不少值得关注的增强特性,特别是JMX、web services、脚本语言支持(采用Rhino脚本引擎JSR 223把JavaScript技术与Java源码进行集成)、数据库连接、支持annotations和安全部分。另外,在JDBC API中还有不少新的特性,包括RowId支持和新增的SQLException子类。

    JDBC 4.0的特性
    得益于Mustang中的Java SE 服务提供商机制,Java开发人员再也不必用类似Class.forName()的代码注册JDBC驱动来明确加载JDBC。当调用DriverManager.getConnection()方法时,DriverManager类将自动设置合适的驱动程序。该特性向后兼容,因此无需对现有的JDBC代码作任何改动。

    通过对Java应用程序访问数据库代码的简化,使得JDBC 4.0有更好的开发体验。JDBC 4.0同时也提供了工具类来改进数据源和连接对象的管理,也改进了JDBC驱动加载和卸载机制。

    有了JDBC 4.0传承自Java SE 5.0 (Tiger)版对元数据的支持功能,Java开发人员可用Annotations明确指明SQL查询。基于标注的SQL查询允许我们通过在Java代码中使用Annotation关键字正确指明SQL查询字符串。这样,我们不必查看JDBC代码和他所调用的数据库两份不同的文件。例如,用一个名为getActiveLoans()方法在贷款处理数据库中获取一个活跃贷款清单,你可以添加@Query(sql="SELECT * FROM LoanApplicationDetails WHERE LoanStatus = 'A'")标注来修饰该方法。

    并且,最终版的Java SE 6开发包(JDK 6)以及其相应的执行期环境(JRE 6)会捆绑一个基于Apache Derby的数据库。这使得Java开发人员无需下载、安装和配置一款单独的数据库产品就能探究JDBC的新特性。

    JDBC 4.0中增加的主要特性包括:
    1.        JDBC驱动类的自动加载
    2.        连接管理的增强
    3.        对RowId SQL类型的支持
    4.        SQL的DataSet实现使用了Annotations
    5.        SQL异常处理的增强
    6.        对SQL XML的支持

    另外,对BLOB/CLOB 的改进支持以及对国际字符集的支持也是JDBC 4.0的特性。这些特性将在随后章节中详细讨论。

    JDBC驱动自动加载
    在JDBC 4.0中,我们不必再使用Class.forName()方法明确加载JDBC驱动。当调用getConnection方法时,DriverManager会尝试从初始化时已经加载的JDBC驱动程序库中选择合适的驱动,以及他在当前应用的同一个类加载器中明确加载使用过的驱动。
    DriverManager中的getConnection和getDrivers方法已作了改进,以支持Java SE 服务提供商机制(SPM)。根据SPM,所谓服务就是一组广为人知的接口和抽象类的集合,而服务提供商就是对某一服务的特定实现。SPM还指明了服务提供商的配置文件存放于META-INF/services目录下。JDBC 4.0的驱动程序库必须包含META-INF/services/java.sql.Driver文件。该文件包含对java.sql.Driver 实现的JDBC驱动文件名。例如,通过JDBC驱动连接Apache Derby数据库,META-INF/services/java.sql.Driver将含有以下路径:
    org.apache.derby.jdbc.EmbeddedDriver

    我们再来快速地看一下如何使用这一新特性加载一个JDBC驱动管理。以下显示的是我们用以加载JDBC驱动的典型范例代码。这里我们假设连接的是Apache Derby数据库,因为该数据库将在本文随后的范例应用中用到:
        Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
        Connection conn =
            DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword);
    但在JDBC 4.0中,我们不必写Class.forName()这一行,我们只需要调用getConnection()方法取得数据库连接。
    请注意,仅在完全独立的模式下可使用该方法取得数据库的连接。如果你使用一些类似数据库连接池等技术管理连接,那么代码将有所不同。

    连接管理
    在JDBC 4.0之前,我们依靠JDBC URL来定义一个数据源连接。现在有了JDBC 4.0,我们只需为标准连接工厂机制提供一组参数,就能获取与任何数据源的连接。Connection和Statement接口增添的新方法为池环境中管理Statement对象提供了更好的连接状态跟踪机制和更大的灵活度。元数据工具(JSR-175)被用来管理活跃连接。我们还能获得元数据信息,如:活跃连接状态,并能指明XA事务的某一连接是标准式(Connection,在独立应用的情况下)、池式(PooledConnection)还是分布式(XAConnection)。该接口仅在诸如WebLogic、WebSphere和JBoss等Java EE应用服务器的事务管理中使用。

    RowId支持
    JDBC 4.0增加了RowID接口以支持ROWID数据类型,Oracle和DB2数据库支持该数据类型。在你需要把大量缺少唯一标识符字段的查询记录放入一个不允许重复对象的Collection容器(如Hashtable)的情况下,RowId很有用。我们可以用ResultSet的getRowId()方法获取RowId,用PreparedStatement的setRowId()方法在查询中使用RowId。

    关于RowId对象需要记住的一件重要事项是,RowId值在数据源之间不可移植。当在PreparedStatement和ResultSet中单独使用set或update方法时,需要想到指明数据源。因此,RowId对象不应被不同的Connection和ResultSet对象共享。

    DatabaseMetaData中的getRowIdLifetime()方法可被用来确定RowId对象的有效存活时间。该方法的可能返回值如表1所列:
    RowId值                                          描述
    ROWID_UNSUPPORTED        Doesn't support ROWID data type.
    ROWID_VALID_OTHER        Lifetime of the RowID is dependent on database vendor implementation.
    ROWID_VALID_TRANSACTION        Lifetime of the RowID is within the current transaction as long as the row in the database table is not deleted.
    ROWID_VALID_SESSION        Lifetime of the RowID is the duration of the current session as long as the row in the database table is not deleted.
    ROWID_VALID_FOREVER        Lifetime of the RowID is unlimited as long as the row in the database table is not deleted.

    基于标注的SQL查询
    JDBC 4.0对标注(Java SE 5新增)作了进一步规范和补充,他允许开发人员不必再写大量代码就能达到联系SQL查询和Java类的目的。并且,通过使用Generics(JSR 014)和元数据(JSR 175) API,我们只要指明查询的输入和输出参数就能将SQL查询与Java对象进行关联。我们还可以将查询结果捆绑在Java类上以加快查询输出的处理。将查询对象置于Java对象之中,我们可以不必像往常一样写所有代码。在Java代码中指明SQL查询,经常用到两种标注:

    Select标注
    Select标注用于在Java类中指明一个选择查询,使get方法能从数据库表中取回数据。表2显示的是Select标注的不同属性及其作用:
    变量                                           类型        描述
    sql                                                            String        SQL Select query string.
    value                                                            String        Same as sql attribute.
    tableName                                            String        Name of the database table against which the sql will be invoked.
    readOnly, connected, scrollable            Boolean        Flags used to indicate if the returned DataSet is read-only or updateable, is connected to the back-end database, and is scrollable when used in connected mode respectively.
    allColumnsMapped                                            Boolean        Flag to indicate if the column names in the sql annotation element are mapped 1-to-1 with the fields in the DataSet.

    这里有一个应用Select标注从贷款数据库中获取所有活跃贷款的例子:
    interface LoanAppDetailsQuery extends BaseQuery {
            @Select("SELECT * FROM LoanDetais where LoanStatus = 'A'")
            DataSet<LoanApplication> getAllActiveLoans();
    }

    Sql标注同样允许I/O参数(参数标记以一个问号后跟一个整型数据表示)。这里是一个参数化sql查询的例子:
    interface LoanAppDetailsQuery extends BaseQuery {
            @Select(sql="SELECT * from LoanDetails
                    where borrowerFirstName= ?1 and borrowerLastName= ?2")
            DataSet<LoanApplication> getLoanDetailsByBorrowerName(String borrFirstName,
                    String borrLastName);
    }

    Update标注
    Update标注用于修饰Query接口方法以更新数据库表中的一条或多条记录。Update标注必须包含一个sql标注类型元素。这里是一个Update标注的例子:
    interface LoanAppDetailsQuery extends BaseQuery {
            @Update(sql="update LoanDetails set LoanStatus = ?1
                    where loanId = ?2")
            boolean updateLoanStatus(String loanStatus, int loanId);
    }

    SQL异常处理的增强特性
    异常处理是Java编程的一个重要部分,特别是对后台关系数据库进行连接或查询时。SQLException是我们用以指出与数据库相关错误的类。JDBC 4.0在SQLException处理中有不少增强。为了在处理SQLException时获得更好的开发体验,JDBC 4.0版作了如下增强:
    1.        新的SQLException子类
    2.        对因果关系的支持
    3.        对改进的for-each循环的支持

    新的SQLException类
    SQLException的新子类提供了一种方法,使Java开发人员能写出更方便改动的错误处理代码。JDBC 4.0介绍了两个新的SQLException型别:
    •        SQL non-transient exception
    •        SQL transient exception

    Non-Transient Exception:除非修正引发SQLException异常的代码,否则该异常在再次尝试相同JDBC操作失败后被抛出。表3显示了JDBC 4.0新增的SQLNonTransientException异常子类(SQL 2003规范中定义了SQLState类的值):

    Exception class                                         SQLState value
    SQLFeatureNotSupportedException          0A
    SQLNonTransientConnectionException     08
    SQLDataException                                           22
    SQLIntegrityConstraintViolationException        23
    SQLInvalidAuthorizationException             28
    SQLSyntaxErrorException                            42

    Transient Exception:当先前执行失败的JDBC操作在没有任何应用级功能干涉的情况下可能成功执行时,该异常被抛出。继承自SQLTransientException的新异常如表4所列:

    Exception class                                SQLState value
    SQLTransientConnectionException        08
    SQLTransactionRollbackException        40
    SQLTimeoutException                      None

    因果关系
    SQLException类现在支持Java SE链式异常机制(又称因果工具),它使我们能在一个JDBC操作中处理多条SQLException异常(如果后台数据库支持多条异常特性)。这种情形发生在执行一条可能会抛出多条SQLException异常的语句时。

    我们可以调用SQLException中的getNextException()方法在异常链中进行迭代。这里是一些处理getNextException()因果关系的范例代码:
    catch(SQLException ex) {
         while(ex != null) {
            LOG.error("SQL State:" + ex.getSQLState());
            LOG.error("Error Code:" + ex.getErrorCode());
            LOG.error("Message:" + ex.getMessage());
            Throwable t = ex.getCause();
            while(t != null) {
                LOG.error("Cause:" + t);
                t = t.getCause();
            }
            ex = ex.getNextException();
        }
    }

    增强的For-Each环
    Java SE 5中,SQLException类通过实现Iterable接口,增加了for-each循环支持的特性。这个循环的轨迹将会包括SQLException和其异常成因。这里的代码片断展示了SQLException中增加的增强型for-each环特性。
    catch(SQLException ex) {
         for(Throwable e : ex ) {
            LOG.error("Error occurred: " + e);
         }
    }

    对国际字符集转换的支持
    以下是JDBC类处理国际字符集的新增特性:
    1.        JDBC数据类型:新增NCHAR、NVARCHAR、LONGNVARCHAR和NCLOB数据类型。
    2.        PreparedStatement:新增setNString、setNCharacterStream和setNClob方法。
    3.        CallableStatement:新增getNClob、getNString和getNCharacterStream方法。
    4.        ResultSet:ResultSet接口新增updateNClob、updateNString和updateNCharacterStream方法。

    对大对象(BLOBs and CLOBs)支持的改进
    以下是JDBC 4.0处理LOBs的新增特性:
    1.        Connection:新增方法(createBlob()、createClob()和createNClob())以创建BLOB、CLOB和NCLOB对象新实例。
    2.        PreparedStatement:新增方法setBlob()、setClob()和setNClob()以使用InputStream对象插入BLOB对象,使用Reader对象插入CLOB和NCLOB对象。
    3.        LOBs:在Blob、Clob和NClob接口中新增方法(free())以释放这些对象所持有的资源。
    现在,让我们来看一看java.sql和javax.jdbc包的新类,以及他们所提供的服务。

    JDBC 4.0 API:新类
    RowId (java.sql)
    正如先前所介绍的,该接口是对数据库中SQL ROWID值的展示。ROWID是一种SQL内建的数据类型,用来标识数据库中的一行特定数据。ROWID经常用于从表中返回查询结果,而这些结果行往往缺少唯一ID字段。

    getRowId和setRowId等CallableStatement、PreparedStatement和ResultSet接口的方法允许程序员访问SQL ROWID值。RowId接口还提供了一个方法(叫getBytes())把ROWID值作为一个byte型数组返回。DatabaseMetaData接口有一个名为getRowIdLifetime的新方法,用以确定某一RowId对象的存活时间。RowId的存活时间范围可以是如下三种类型:
    1.        创建RowId的数据库事务持续时间
    2.        创建RowId的会话持续时间
    3.        数据库对应的记录还未被删除的持续时间

    DataSet (java.sql)
    DataSet接口提供了对执行SQL Query后所返回数据类型的安全检查。DataSet还可以运行在连接或非连接模式。在连接模式下,DataSet类似于ResultSet的功能;而在非连接模式下,他类似于CachedRowSet的功能。由于DataSet继承自List接口,因此我们能对查询返回的记录行进行迭代。

    对已有的类,JDBC 4.0也新增了不少方法。比如,Connection新增了createSQLXML和createSQLXML方法,ResultSet新增了getRowId方法。

    范例应用
    本文所示的范例应用是一个贷款处理应用软件,他有一个贷款搜索页面,用户可以通过输入贷款ID提交查询表,以获取贷款详情。贷款搜索页面调用一个控制器对象,而该对象又调用一个DAO对象访问后台数据库,以取回贷款详情。这些详情包括贷款人、贷款数额、贷款截至日期等信息,并显示在贷款详情屏幕上。后台数据库中,我们有一个名为LoanApplicationDetails的表,来存储贷款软件的详情。

    该范例应用的用例是通过指定贷款ID来获取贷款详情。当贷款已经登记并将抵押物与利息挂钩后,贷款详情就可以被获取。表5显示了贷款处理应用软件项目的详情。
    Name                            Value
    Project Name        JdbcApp
    Project Directory        c:\dev\projects\JdbcApp
    DB Directory        c:\dev\dbservers\apache\derby
    JDK Directory        c:\dev\java\jdk_1.6.0
    IDE Directory        c:\dev\tools\eclipse
    Database        Apache Derby 10.1.2.1
    JDK                        6.0 (beta 2 release)
    IDE                        Eclipse 3.1
    Unit Testing        JUnit 4
    Build                        Ant 1.6.5

    下表所列的是我们连接贷款详情Apache Derby数据库所需的JDBC参数。这些参数存放于一个名为derby.properties的文本文件中,并置于项目的etc/jdbc目录下(见表6)。

    Name                           Value
    JDBC Driver File        LoanApp\META-INF\services\java.sql.driver
    Driver                       org.apache.derby.ClientDriver
    URL                       jdbc:derby:derbyDB
    User Id                       user1
    Password                       user1

    请注意:Apache Derby数据库提供了两种JDBC驱动:嵌入式驱动(org.apache.derby.jdbc.EmbeddedDriver)和客户端/服务器驱动(org.apache.derby.jdbc.ClientDriver)。我在范例应用中使用客户端/服务器版驱动。
    以下是使用ij工具来启动Derby数据库服务器并创建新数据库的命令。

    要启动Derby网络服务器,需开启一个命令行窗口,并运行如下命令(请根据你本机的环境改写DERBY_INSTALL和JAVA_HOME环境变量)。
    set DERBY_INSTALL=C:\dev\dbservers\db-derby-10.1.2.1-bin
    set JAVA_HOME=C:\dev\java\jdk1.6.0
    set DERBY_INSTALL=C:\dev\dbservers\db- derby-10.1.3.1-bin
    set CLASSPATH=%CLASSPATH%;%DERBY_INSTALL%\lib\derby.jar;
                    %DERBY_INSTALL%\lib\derbytools.jar;
                    %DERBY_INSTALL%\lib\derbynet.jar;

    cd %DERBY_INSTALL%\frameworks\NetworkServer\bin
    startNetworkServer.bat

    要连接数据库服务器并创建测试数据库,需开启另一个命令行窗口并运行以下命令。请确保DERBY_INSTALL和JAVA_HOME环境变量符合你本机的环境。
    set JAVA_HOME=C:\dev\java\jdk1.6.0
    set DERBY_INSTALL=C:\dev\dbservers\db-derby-10.1.3.1-bin
    set CLASSPATH=%DERBY_INSTALL%\lib\derbyclient.jar;
                    %DERBY_INSTALL%\lib\derbytools.jar;.

    %JAVA_HOME%\bin\java org.apache.derby.tools.ij
    connect 'jdbc:derby://localhost:1527/LoanDB;create=true';

    测试
    要编译Java源代码,classpath需包括derby.jar和junit4.jar文件,这两个文件在项目的lib目录下。Classpath还需包括etc、etc/jdbc和etc/log4j目录,这样应用程序才能访问JDBC属性文件和Log4J配置文件。我创建了一个Ant构建脚本(在JdbcApp/build目录下)来自动完成编译和打包Java源代码的工作。

    用于测试贷款详情数据库访问对象的测试类名为LoanAppDetailsDAOTest。我们传入贷款ID和贷款人参数就可以获取贷款详情。
    以下部分显示了JDBC 4.0中自动加载JDBC驱动和基于标注的SQL查询特性的代码范例。

    JDBC驱动的自动加载
    BaseDAO抽象类有一个名为getConnection的方法用以获得一个数据库连接。以下代码片断显示了该方法(注意,我们不必注册JDBC驱动)。只要java.sql.Driver文件中有合适的驱动程序类名(org.apache.derby.jdbc.ClientDriver ),JDBC驱动将被自动加载。
    protected Connection getConnection() throws DAOException {
            // Load JDBC properties first
            if (jdbcUrl == null || jdbcUser == null ||
                            jdbcPassword == null) {
                    loadJdbcProperties();
            }
            // Get Connection
            Connection conn = null;
            try {
                    conn = DriverManager.getConnection(jdbcUrl, jdbcUser,
                                    jdbcPassword);
            } catch (SQLException sqle) {
                    throw new DAOException("Error in getting a DB connection.",
                                    sqle);
            }
            return conn;
    }

    SQL标注
    LoanAppDetailsQuery接口有标注了的SQL查询,用以获取活跃贷款清单(criteria is loanstatus="A")和某贷款人的贷款详情(在一个贷款人有多笔贷款的情况下)。在上文中,我们已经了解过了这些SQL标注。这里的范例代码显示了我们如何使用标注来调用已定义的SQL查询。
    public DataSet<LoanAppDetails> getAllActiveLoans() throws Exception {
            // Get Connection
            Connection conn = getConnection();
            LoanAppDetailsQuery query = null;
            DataSet<LoanAppDetails> loanDetails = null;
            query = QueryObjectFactory.createQueryObject (
                            LoanAppDetailsQuery.class, conn);
            loanDetails = query.getAllActiveLoans();
            return loanDetails;
    }

    public DataSet<LoanAppDetails> getLoanDetailsByBorrowerName(
                    String borrFirstName, String borrLastName) throws Exception {
            // Get Connection
            Connection conn = getConnection();
            LoanAppDetailsQuery query = null;
            DataSet<LoanAppDetails> loanDetails = null;
            query = QueryObjectFactory.createQueryObject(
                            LoanAppDetailsQuery.class, conn);
            loanDetails = query.getLoanDetailsByBorrowerName(
                            borrFirstName,borrLastName);
            return loanDetails;
    }

    结论
    JDBC 4.0在SQL方面为开发者提供了更好的开发体验。JDBC 4.0的另一个目标是为API增加更丰富的工具以提供企业级JDBC特性管理JDBC资源。并且,JDBC 4.0 API还提供了JDBC驱动的移植方式,使其符合J2EE连接器架构(JCA)规范。这为JDBC厂商提供了向JDBC连接器迁移的能力。在面向企业服务的架构(SPA)中使用JDBC数据源,该移植方式很重要。在SOA中,JDBC数据源可被部署在另一个企业服务总线(ESB)架构内,而不需要为JDBC数据源另写一份ESB实现代码。

    本文中,我们了解了RowId支持,JDBC驱动加载和基于标注的SQL等JDBC 4.0的增强特性。未来,JDBC 4.0还将增加更多特性以支持SQL:2003。请参阅特性文档,以获取更多有关JDBC 4.0特性的信息。

    Resources
    Matrix-与Java共舞
    Sample Application Code

    Srini Penchikala是Flagstar Bank的一位信息系统问题专家。
     

    ajax名家杂谈之一二

    孟岩:
    广义的Ajax并不是基于JavaScript、XML/JSON的一些编程技巧,而是"Ajax与REST、RSS、ATOM、Microformats、mashup等技术结合起来,勾画出了下一代Web技术架构的蓝图,这是一个简单的、富客户端的、异步的、面向资源的、全双工的、初具语义特征的、以标准格式的数据为中心的、服务化的的架构,是一个计算资源分布更合理、用户体验更好、开发更简单、mashup无所不在的、更具可扩展性的技术架构。"
     
    李琨
    实际上我比较看好完全基于XAML的WPF,因为从技术本身来说是最先进的。将来的Web表现层开发一定会走到这种方式。Silverlight的UI技术还是基于DHTML的,所以现在这一两年对于开发者比较有吸引力。

    星期三, 五月 16, 2007

    用List传递Resultset对象 得到的不同类型对象

    public static ArrayList<LinkedHashMap> delRes(String sql) {
        ArrayList<LinkedHashMap> list = new ArrayList<LinkedHashMap>();

        Connection con = null;
        PreparedStatement stmt = null;
        ResultSetMetaData metaData=null;
        try {
            con = ConDB.getCon();
            stmt = (PreparedStatement) con.prepareStatement(sql);
            ResultSet result = stmt.executeQuery();
            metaData=result.getMetaData();
            while (result.next()) {
                LinkedHashMap v = new LinkedHashMap();
                for (int i = 1; i <= metaData.getColumnCount (); i++)
                    v.put(metaData.getColumnLabel(i),result.getObject(i));

                list.add(v);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null) {
                stmt.close();
                }
                if (con != null) {
                    con.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return list;
    }
     
     
    待确认方法,利用反射
    ResultSetMetaData rsm=rs.getMetaData();
    Object domain=null;
    while(rs.next()){
        domain=Class.forName("Domain").newInstance();
        for(int i=1;i<=rsm.getColumnCount();i++){
            String recordValue= rs.getString(rsm.getColumnName(i));
            Method m=domain.getClass().getMethod("set"+rsm.getColumnName(i),new Class[]{recordValue.getClass()});
            m.invoke(domain,new Object[]{recordValue});
       }
       list.add(domain);
    }
     

    星期二, 五月 01, 2007

    Info/Common HTTPStatusCodes

    Code Message
    100 Continue
    101 Switching Protocols
    102 Processing
    200 OK
    The request has succeeded.
    201 Created
    202 Accepted
    203 Non-Authoritative Information
    204 No Content
    205 Reset Content
    206 Partial Content
    207 Multi-Status
    300 Multiple Choices
    301 Moved Permanently
    The document has moved URL here
    302 Found
    The document has moved URL here
    303 See Other
    The answer to your request is located URL here
    304 Not Modified
    A cached copy will be used
    305 Use Proxy
    306 unused
    307 Temporary Redirect
    400 Bad Request
    Your browser sent a request that this server could not understand
    401 Authorization Required
    This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.
    402 Payment Required
    403 Forbidden
    You don't have permission to access on this server
    404 Not Found
    T he requested URL was not found on this server
    405 Method Not Allowed
    The requested method GET is not allowed for the URL
    406 Not Acceptable
    407 Proxy Authentication Required
    408 Request Time-out
    Server timeout waiting for the HTTP request from the client
    409 Conflict
    410 Gone
    The requested resource is no longer available on this server and there is no forwarding address. Please remove all references to this resource
    411 Length Required
    A request of the requested method GET requires a valid Content-length
    412 Precondition Failed
    The precondition on the request for the URL evaluated to false
    413 Request Entity Too Large
    The requested resource does not allow request data with GET requests, or the amount of data provided in the request exceeds the capacity limit
    414 Request-URI Too Large
    The requested URL's length exceeds the capacity limit for this server
    415 Unsupported Media Type
    The supplied request data is not in a format acceptable for processing by this resource.
    416 Requested Range Not Satisfiable
    417 Expectation Failed
    418 unused
    419 unused
    420 unused
    421 unused
    422 Unprocessable Entity
    423 Locked
    424 Failed Dependency
    425 No code
    426 Upgrade Required
    500 Internal Server Error
    The server encountered an internal error or misconfiguration and was unable to complete your request
    501 Method Not Implemented
    GET to URL not supported
    502 Bad Gateway
    The proxy server received an invalid response from an upstream server
    503 Service Temporarily Unavailable
    The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
    504 Gateway Time-out
    505 HTTP Version Not Supported
    506 Variant Also Negotiates
    A variant for the requested resource URL is itself a negotiable resource. This indicates a configuration error.
    507 Insufficient Storage
    508 unused
    509 unused
    510 Not Extended