Java community

【转载】驯服 Tiger: 并发集合
驯服 Tiger: 并发集合
英文原文
内容:
介绍 Queue 接口
使用基本队列
使用阻塞队列
使用 ConcurrentMap 实现
使用 CopyOnWriteArrayList 和 CopyOnWriteArraySet
结束语
参考资料
关于作者
对本文的评价
相关内容:
Java theory and practice: Concurrency made simple (sort of)
Java theory and practice: Concurrent collections classes
Introduction to Java threads
IBM developer kits for the Java platform (downloads)
超越 Map、Collection、List 和 Set

级别: 中级

John Zukowskijaz@zukowski.net
总裁, JZ Ventures, Inc.
2004 年 6 月

Doug Lea 最初编写的 util.concurrent 包变成了 JSR-166 ,然后又变成了 J2SE 平台的 Tiger 版本。这个新库提供的是并发程序中通常需要的一组实用程序。如果对于优化对集合的多线程访问有兴趣,那么您就找对地方了。

在 Java 编程的早期阶段,位于 Oswego 市的纽约州立大学(SUNY) 的一位教授决定创建一个简单的库,以帮助开发人员构建可以更好地处理多线程情况的应用程序。这并不是说用现有的库就不能实现,但是就像有了标准网络库一样,用经过调试的、可信任的库更容易自己处理多线程。在 Addision-Wesley 的一本相关书籍的帮助下,这个库变得越来越流行了。最终,作者 Doug Lea 决定设法让它成为 Java 平台的标准部分 —— JSR-166。这个库最后变成了 Tiger 版本的 java.util.concurrent 包。在这篇新的 驯服 Tiger 技巧中,我们将探讨 Collection Framework 中新的 Queue 接口、这个接口的非并发和并发实现、并发 Map 实现和专用于读操作大大超过写操作这种情况的并发 ListSet 实现。

介绍 Queue 接口
java.util 包为集合提供了一个新的基本接口:java.util.Queue。虽然肯定可以在相对应的两端进行添加和删除而将 java.util.List 作为队列对待,但是这个新的 Queue 接口提供了支持添加、删除和检查集合的更多方法,如下所示:

public boolean offer(Object element) public Object remove() public Object poll() public Object element() public Object peek()

基本上,一个队列就是一个先入先出(FIFO)的数据结构。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。remove()poll() 方法都是从队列中删除第一个元素(head)。remove() 的行为与 Collection 接口的版本相似,但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。后两个方法 element()peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时,element() 抛出一个异常,而 peek() 返回 null。

使用基本队列
在 Tiger 中有两组 Queue 实现:实现了新 BlockingQueue 接口的和没有实现这个接口的。我将首先分析那些没有实现的。

在最简单的情况下,原来有的 java.util.LinkedList 实现已经改造成不仅实现 java.util.List 接口,而且还实现 java.util.Queue 接口。可以将集合看成这两者中的任何一种。清单 1 显示将 LinkedList 作为 Queue 使用的一种方法:

清单 1. 使用 Queue 实现
Queue queue = new LinkedList(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); // Head of queue should be One System.out.println("Head of queue is: " + queue.poll());

再复杂一点的是新的 java.util.AbstractQueue 类。这个类的工作方式类似于 java.util.AbstractListjava.util.AbstractSet 类。在创建自定义集合时,不用自己实现整个接口,只是继承抽象实现并填入细节。使用 AbstractQueue 时,必须为方法 offer() poll()peek() 提供实现。像 add()addAll() 这样的方法修改为使用 offer(),而 clear()remove() 使用 poll()。最后,element() 使用 peek()。当然可以在子类中提供这些方法的优化实现,但是不是必须这么做。而且,不必创建自己的子类,可以使用几个内置的实现, 其中两个是不阻塞队列: PriorityQueueConcurrentLinkedQueue

PriorityQueueConcurrentLinkedQueue 类在 Collection Framework 中加入两个具体集合实现。PriorityQueue 类实质上维护了一个有序列表。加入到 Queue 中的元素根据它们的天然排序(通过其java.util.Comparable 实现)或者根据传递给构造函数的 java.util.Comparator 实现来定位。将清单 2 中的 LinkedList 改变为 PriorityQueue 将会打印出 Four 而不是 One,因为按字母排列 —— 字符串的天然顺序 —— Four 是第一个。ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大小,ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。

使用阻塞队列
新的 java.util.concurrent 包在 Collection Framework 中可用的具体集合类中加入了 BlockingQueue 接口和五个阻塞队列类。假如不熟悉阻塞队列概念,它实质上就是一种带有一点扭曲的 FIFO 数据结构。不是立即从队列中添加或者删除元素,线程执行操作阻塞,直到有空间或者元素可用。BlockingQueue 接口的 Javadoc 给出了阻塞队列的基本用法,如清单 2 所示。生产者中的 put() 操作会在没有空间可用时阻塞,而消费者的 take() 操作会在队列中没有任何东西时阻塞。

清单 2. 使用 BlockingQueue
class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { queue.put(produce()); } } catch (InterruptedException ex) { ... handle ...} } Object produce() { ... } } class Consumer implements Runnable { private final BlockingQueue queue; Consumer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { consume(queue.take()); } } catch (InterruptedException ex) { ... handle ...} } void consume(Object x) { ... } } class Setup { void main() { BlockingQueue q = new SomeQueueImplementation(); Producer p = new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(c1).start(); new Thread(c2).start(); } }

五个队列所提供的各有不同:

  • ArrayBlockingQueue:一个由数组支持的有界队列。
  • LinkedBlockingQueue:一个由链接节点支持的可选有界队列。
  • PriorityBlockingQueue:一个由优先级堆支持的无界优先级队列。
  • DelayQueue:一个由优先级堆支持的、基于时间的调度队列。
  • SynchronousQueue:一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。

前两个类 ArrayBlockingQueueLinkedBlockingQueue 几乎相同,只是在后备存储器方面有所不同,LinkedBlockingQueue 并不总是有容量界限。无大小界限的 LinkedBlockingQueue 类在添加元素时永远不会有阻塞队列的等待(至少在其中有 Integer.MAX_VALUE 元素之前不会)。

PriorityBlockingQueue 是具有无界限容量的队列,它利用所包含元素的 Comparable 排序顺序来以逻辑顺序维护元素。可以将它看作 TreeSet 的可能替代物。例如,在队列中加入字符串 One、Two、Three 和 Four 会导致 Four 被第一个取出来。对于没有天然顺序的元素,可以为构造函数提供一个 Comparator 。不过对 PriorityBlockingQueue 有一个技巧。从 iterator() 返回的 Iterator 实例不需要以优先级顺序返回元素。如果必须以优先级顺序遍历所有元素,那么让它们都通过 toArray() 方法并自己对它们排序,像 Arrays.sort(pq.toArray())

新的 DelayQueue 实现可能是其中最有意思(也是最复杂)的一个。加入到队列中的元素必须实现新的 Delayed 接口(只有一个方法 —— long getDelay(java.util.concurrent.TimeUnit unit))。因为队列的大小没有界限,使得添加可以立即返回,但是在延迟时间过去之前,不能从队列中取出元素。如果多个元素完成了延迟,那么最早失效/失效时间最长的元素将第一个取出。实际上没有听上去这样复杂。清单 3 演示了这种新的阻塞队列集合的使用:

清单 3. 使用 DelayQueue 实现
import java.util.*; import java.util.concurrent.*; public class Delay { /** * Delayed implementation that actually delays */ static class NanoDelay implements Delayed { long trigger; NanoDelay(long i) { trigger = System.nanoTime() + i; } public int compareTo(Object y) { long i = trigger; long j = ((NanoDelay)y).trigger; if (i < j) return -1; if (i > j) return 1; return 0; } public boolean equals(Object other) { return ((NanoDelay)other).trigger == trigger; } public boolean equals(NanoDelay other) { return ((NanoDelay)other).trigger == trigger; } public long getDelay(TimeUnit unit) { long n = trigger - System.nanoTime(); return unit.convert(n, TimeUnit.NANOSECONDS); } public long getTriggerTime() { return trigger; } public String toString() { return String.valueOf(trigger); } } public static void main(String args[]) throws InterruptedException { Random random = new Random(); DelayQueue queue = new DelayQueue(); for (int i=0; i < 5; i++) { queue.add(new NanoDelay(random.nextInt(1000))); } long last = 0; for (int i=0; i < 5; i++) { NanoDelay delay = (NanoDelay)(queue.take()); long tt = delay.getTriggerTime(); System.out.println("Trigger time: " + tt); if (i != 0) { System.out.println("Delta: " + (tt - last)); } last = tt; } } }

这个例子首先是一个内部类 NanoDelay,它实质上将暂停给定的任意纳秒(nanosecond)数,这里利用了 System 的新 nanoTime() 方法。然后 main() 方法只是将 NanoDelay 对象放到队列中并再次将它们取出来。如果希望队列项做一些其他事情,就需要在 Delayed 对象的实现中加入方法,并在从队列中取出后调用这个新方法。(请随意扩展 NanoDelay 以试验加入其他方法做一些有趣的事情。)显示从队列中取出元素的两次调用之间的时间差。如果时间差是负数,可以视为一个错误,因为永远不会在延迟时间结束后,在一个更早的触发时间从队列中取得项。

SynchronousQueue 类是最简单的。它没有内部容量。它就像线程之间的手递手机制。在队列中加入一个元素的生产者会等待另一个线程的消费者。当这个消费者出现时,这个元素就直接在消费者和生产者之间传递,永远不会加入到阻塞队列中。

使用 ConcurrentMap 实现
新的 java.util.concurrent.ConcurrentMap 接口和 ConcurrentHashMap 实现只能在键不存在时将元素加入到 map 中,只有在键存在并映射到特定值时才能从 map 中删除一个元素。

有一个新的 putIfAbsent() 方法用于在 map 中进行添加。这个方法以要添加到 ConcurrentMap 实现中的键的值为参数,就像普通的 put() 方法,但是只有在 map 不包含这个键时,才能将键加入到 map 中。如果 map 已经包含这个键,那么这个键的现有值就会保留。putIfAbsent() 方法是原子的。如果不调用这个原子操作,就需要从适当的同步块中调用清单 4 中的代码:

清单 4. 等价的 putIfAbsent() 代码
if (!map.containsKey(key)) { return map.put(key, value); } else { return map.get(key); }

putIfAbsent() 方法一样,重载后的 remove() 方法有两个参数 —— 键和值。在调用时,只有当键映射到指定的值时才从 map 中删除这个键。如果不匹配,那么就不删除这个键,并返回 false。如果值匹配键的当前映射内容,那么就删除这个键。清单 5 显示了这种操作的等价源代码:

清单 5. 等价的 remove() 代码
if (map.get(key).equals(value)) { map.remove(key); return true; } else { return false; }

使用 CopyOnWriteArrayList 和 CopyOnWriteArraySet
在 Doug Lea 的 Concurrent Programming in Java 一书的第 2 章第 2.4.4 节(请参阅 参考资料)中,对 copy-on-write 模式作了最好的描述。实质上,这个模式声明了,为了维护对象的一致性快照,要依靠不可变性(immutability)来消除在协调读取不同的但是相关的属性时需要的同步。对于集合,这意味着如果有大量的读(即 get()) 和迭代,不必同步操作以照顾偶尔的写(即 add())调用。对于新的 CopyOnWriteArrayListCopyOnWriteArraySet 类,所有可变的(mutable)操作都首先取得后台数组的副本,对副本进行更改,然后替换副本。这种做法保证了在遍历自身更改的集合时,永远不会抛出 ConcurrentModificationException。遍历集合会用原来的集合完成,而在以后的操作中使用更新后的集合。

这些新的集合,CopyOnWriteArrayListCopyOnWriteArraySet,最适合于读操作通常大大超过写操作的情况。一个最常提到的例子是使用监听器列表。已经说过,Swing 组件还没有改为使用新的集合。相反,它们继续使用 javax.swing.event.EventListenerList 来维护它们的监听器列表。

如清单 6 所示,集合的使用与它们的非 copy-on-write 替代物完全一样。只是创建集合并在其中加入或者删除元素。即使对象加入到了集合中,原来的 Iterator 也可以进行,继续遍历原来集合中的项。

清单 6. 展示一个 copy-on-write 集合
import java.util.*; import java.util.concurrent.*; public class CopyOnWrite { public static void main(String args[]) { List list1 = new CopyOnWriteArrayList(Arrays.asList(args)); List list2 = new ArrayList(Arrays.asList(args)); Iterator itor1 = list1.iterator(); Iterator itor2 = list2.iterator(); list1.add("New"); list2.add("New"); try { printAll(itor1); } catch (ConcurrentModificationException e) { System.err.println("Shouldn't get here"); } try { printAll(itor2); } catch (ConcurrentModificationException e) { System.err.println("Will get here."); } } private static void printAll(Iterator itor) { while (itor.hasNext()) { System.out.println(itor.next()); } } }

这个示例程序用命令行参数创建 CopyOnWriteArrayListArrayList 这两个实例。在得到每一个实例的 Iterator 后,分别在其中加入一个元素。当 ArrayList 迭代因一个 ConcurrentModificationException 问题而立即停止时,CopyOnWriteArrayList 迭代可以继续,不会抛出异常,因为原来的集合是在得到 iterator 之后改变的。如果这种行为(比如通知原来一组事件监听器中的所有元素)是您需要的,那么最好使用 copy-on-write 集合。如果不使用的话,就还用原来的,并保证在出现异常时对它进行处理。

结束语
在 J2SE 平台的 Tiger 版中有许多重要的增加。除了语言级别的改变,如一般性支持,这个库也许是最重要的增加了,因为它会被最广泛的用户使用。不要忽视加入到平台中的其他包,像 Java Management Extensions (JMX),但是大多数其他重要的库增强只针对范围很窄的开发人员。但是这个库不是。除了用于锁定和原子操作的其他并发实用程序,这些类也会经常使用。尽早学习它们并利用它们所提供的功能。

参考资料

关于作者
Author photoJohn Zukowski 为 JZ Ventures, Inc. 提供战略性 Java 咨询,并与 SavaJe Technologies 合作开发下一代移动电话平台。他的最新著作有 Mastering Java 2, J2SE 1.4 (Sybex,2002 年 4 月)和 Learn Java with JBuilder 6 (Apress,2002 年 3 月)。可以通过 jaz@zukowski.net 与他联系。
【转载】J2EE 应用程序中的数据管理和数据持久性
J2EE 应用程序中的数据管理和数据持久性
英文原文
内容:
Java 对象序列化
Java 数据库连接(JDBC)
从 Java 代码调用存储过程
包装
参考资料
作者简介
对本文的评价
相关内容:
J2EE 探险者:持久数据管理,第 2 部分
IBM developer kits for the Java platform (downloads)
JDBC 存储提供了多种数据管理的可能

级别: 中级

G.V.B. SubrahmanyamSubrahmanyam.vb.gampa@citigroup.com) , 顾问, Citigroup Technologies
Shankar Itchapurapushankar.i@polaris.co.in) , 顾问, Citigroup Technologies

2004 年 7 月

本文分析了在 Java 平台上可用的两个数据管理策略:Java 对象序列化和 Java 数据库连接(JDBC)。尽管本质上这两种数据管理策略并不存在孰优孰劣的问题,但在管理企业信息系统时,JDBC 轻而易举地得以胜出。在本文中,Java 开发人员 G.V.B. Subrahmanyam 和 Shankar Itchapurapu 对序列化和 JDBC都进行了介绍,并通过讨论和实例来向您展示了 JDBC 是您的最佳选择的原因。

当您正在建立企业信息系统时,需要确保以某种有效的方式存储、检索和显示企业数据。对于所有业务而言,数据都是独一无二的最大资产。所有软件系统都涉及数据,因此,数据的重要性是无论如何强调都不过分的。

应用程序的数据管理功能包括四个基本操作,通常也需要对企业数据执行这四个操作,它们是:建立、检索、更新删除(即 CRUD)。管理在企业系统的数据涉及在很长一段时间范围之内,始终如一地、成功地执行 CRUD 操作,而不必频繁地更改实际执行这些操作的代码。换句话说,管理数据意味着开发稳健的、可扩展和可维护的软件系统,以确保成功地进行 CRUD 操作,在软件的生命期中能够以一致的方式执行操作。

本文讨论了 J2EE 中的两种可用数据管理策略:Java 对象序列化和 Java 数据库连接(JDBC)。我们将查看这两种方法的优缺点。这两种数据管理策略实质上不存在孰优孰劣。在特定实现中,策略的可用性取决于项目的范围(出现在系统环境中的活动的活动范围),系统的上下文(驱动系统/子系统运行时的值的集合),以及其他的外部因素。然而,Java 序列化并不适合于企业系统,其数据需要用一种定义良好的结构(如RDBMS)来组织。我们首先将快速浏览 Java 对象序列化,然后查看 JDBC 更重要的一些方面,从而了解后者是如何实现前者所缺乏的一些关键特性的。

本文并不打算对 Java 对象序列化或者 JDBC 进行全面介绍。有关这两项技术的更多信息,请回顾参考资料小节。

Java 对象序列化
对象序列化是最简单的 Java 持久性策略。对象序列化是一个将对象图平面化为一个字节的线性序列的过程。对象图是作为对象继承、关联和聚合的结果而实现的一些关系式。对象的非暂态实例属性以字节的形式被写入到持久存储中。实例属性的值就是执行时间序列化时内存中的值。如果一个 Java 对象是可序列化的,那么它至少必须实现 java.io.Serializable 接口,该接口具有如下所示的结构:

package java.io; public interface Serializable {}

您可以看到,java.io.Serializable 接口并没有声明任何方法。它是一个记号或者标记接口。它告诉 Java 运行时环境,该实现类是可序列化的。列表 1 显示实现该接口的一个示例类。

列表 1. MySerializableObject.java
import java.io.Serializable; public class MySerializableObject extends MySuperClass implements Serializable { private String property1 = null; private String property2 = null; public String getProperty1() { return property1; } public void setProperty1(String val) { property1 = val; } public String getProperty2() { return property2; } public void setProperty2(String val) { property2 = val; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject (getProperty1 ()); out.writeObject (getProperty2 ()); } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { setProperty1 ((String) in.readObject ()); setProperty2 ((String) in.readObject ()); } }

无需自己实现 writeObject(...)readObject(...) 方法来执行序列化;Java 运行时环境具有使这些方法可用的默认实现。然而,您可以重写这些方法,提供如何存储对象状态的您自己的实现。

关于序列化,您需要记住一些要点。首先,在序列化期间,整个对象图(即,所有父类和被引用类)都将被序列化。其次, Serializable 类的所有实例变量自身都应该是可序列化的,除非已经特别声明它们为暂态,或者已经重写 writeObject(...)readObject(...) 来只序列化那些可序列化的实例变量。如果违反了后一规则,在运行时将出现一个异常。

每个后续 J2SE 版本都对对象序列化系统进行少量的增加。J2SE 1.4 也相应地向 ObjectOutputStream and ObjectInputStream 增加 writeUnshared() and readUnshared()方法。通常,一个序列化的流只包含任何给定对象的一个序列化实例,并且共享对该对象引用的其他对象可以对它进行后向引用。通常期望序列化一个对象独立于其他对象可能维护的任何引用。非共享的读写方法允许对象作为新的、独一无二的对象被序列化,从而获得一个类似于对象克隆但开销更少的效果。

Java 对象序列化存在的问题
序列化涉及到将对象图从内存具体化到持久存储(例如硬盘)中。这涉及到大量 I/O 开销。通常,对应用程序而言,序列化并不是最佳选择:

  • 管理几十万兆字节的存储数据
  • 频繁地更新可序列化对象

对存储企业数据而言,序列化是一个错误选择,因为:

  • 序列化的字节流只对 Java 语言是可读的。这是一个重大缺陷,因为企业系统通常是异构的,许多应用程序要与其他应用程序共同处理相同的数据。

  • 对象检索涉及大量的 I/O 开销。

  • 没有一个用来从序列化对象图中检索获取数据的查询语言。

  • 序列化没有内置的安全机制。

  • 序列化本身并不提供任何事务控制机制,因此不能在那些需要并发访问从而不使用辅助 API 的应用程序中使用它。

Java 数据库连接(JDBC)
Java 数据库连接(JDBC)是一个标准的 API,它使用 Java 编程语言与数据库进行交互。诸如 JDBC 的调用级接口是编程接口,它们允许从外部访问 SQL 命令来处理和更新数据库中的数据。通过提供与数据库连接的库例程,它们允许将 SQL 调用集成到通用的编程环境中。特别是,JDBC 有一个使接口变得极其简单和直观的例程的丰富收集。

在下面几个小节中,我们将查看通过 JDBC 与数据库连接所涉及的一些步骤。我们将特别关注与 Java 对象序列化相比,JDBC 是如何成为一个企业数据管理策略的。

建立一个数据库连接
在利用 JDBC 做任何其他事情之前,需要从驱动程序供应商那里获取数据库驱动程序,并且将该库添加到类路径中。一旦完这项工作,就可以在 Java 程序中使用类似于下面所示的代码来实现实际的连接。

Class.forName(); Java.sql.Connection conn = DriverManager.getConnection();

Java 对象序列化并不需要这个该步骤,因为使用序列化来执行持久性操作并不需要 DBMS。 序列化是一个基于文件的机制;因此,在序列化一个对象之前,需要在目标文件系统中打开一个 I/O 流。

创建 JDBC Statement 和 PreparedStatement
可以用 JDBC Statement 对象将 SQL 语句发送到数据库管理系统(DBMS),并且不应该将该对象与 SQL 语句混淆。 JDBC Statement 对象是与打开连接有关联,而不是与任何单独的 SQL 语句有关联。可以将 JDBC Statement 对象看作是位于连接上的一个通道,将一个或多个(您请求执行的)SQL 语句传送给 DBMS。

为了创建 Statement 对象,您需要一个活动的连接。通过使用我们前面所创建的 Connection 对象 con——下面的代码来完成这项工作。

Statement stmt = con.createStatement();

到目前为止,我们已经有了一个 Statement 对象,但是还没有将对象传递到 DBMS 的 SQL 语句。

当数据库接收到语句时,数据库引擎首先会分析该语句并查找句法错误。一旦完成对语句的分析,数据库就必须计算出执行它的最有效方法。在计算上,这可能非常昂贵。数据库会检查哪些索引可以提供帮助,如果存在这样的索引的话,或者检查是否应该完全读取表中的所有行。数据库针对数据进行统计,找出最佳的执行方式。一旦创建好查询计划,数据库引擎就可以执行它。

生成这样一个计划会占用 CPU 资源。理想情况是,如果我们两次发送相同的语句到数据库,那么我们希望数据库重用第一个语句的访问计划,我们可以使用 PreparedStatement 对象来获得这种效果。

这里有一个主要的特性是,将 PreparedStatement 与其超类 Statement 区别开来:与 Statement 不同,在创建 PreparedStatement 时,会提供一个 SQL 语句。然后了立即将它发送给 DBMS,在那里编译该语句。因而, PreparedStatement 实际上是作为一 个通道与连接和被编译的 SQL 语句相关联的。

那么,它的优势是什么呢?如果需要多次使用相同的查询或者不同参数的类似查询,那么利用 PreparedStatement,语句,只需被 DBMS 编译和优化一次即可。与使用正常的 Statement 相比,每次使用相同的 SQL 语句都需要重新编译一次。

还可以通过 Connection 方法创建PreparedStatement 。下面代码显示了如何创建一个带有三个输入参数的参数化了的 SQL 语句。

PreparedStatement prepareUpdatePrice = con.prepareStatement( "UPDATE Sells SET price = ? WHERE bar = ? AND beer = ?");

注意,Java 序列化不支持类似于 SQL 的查询语言。使用 Java 序列化访问对象属性的惟一途径就是反序列化该对象,并调用该对象上的 getter/accessor 方法。反序列化一个完整的对象在计算上可能很昂贵,尤其是在程序的生命期中,应用程序需要重复执行它。

在执行 PreparedStatement 之前,需要向参数提供值。通过调用 PreparedStatement 中定义的 setXXX() 方法可以实现它。最常使用的方法是 setInt()setFloat()setDouble(),以及 setString()。每次执行已准备的声明之前,都需要设置这些值。

执行语句和查询
执行 JDBC 中的 SQL 语句的方式是根据 SQL 语句的目的而变化的。DDL(数据定义语言)语句(例如表建立和表更改语句)和更新表内容的语句都是通过使用 executeUpdate() 执行的。列表 2 中包含 executeUpdate() 语句的实例。

列表 2. 实际运行中的 executeUpdate()
Statement stmt = con.createStatement(); stmt.executeUpdate("CREATE TABLE Sells " + "(bar VARCHAR2(40), beer VARCHAR2(40), price REAL)" ); stmt.executeUpdate("INSERT INTO Sells " + "VALUES ('Bar Of Foo', 'BudLite', 2.00)" ); String sqlString = "CREATE TABLE Bars " + "(name VARCHAR2(40), address VARCHAR2(80), license INT)" ; stmt.executeUpdate(sqlString);

我们将通过先前插入的参数值(如上所示)执行 PreparedStatement ,然后在这之上调用 executeUpdate(),如下所示:

int n = prepareUpdatePrice.executeUpdate() ;

相比之下,查询期望返回一个行作为它的结果,并且并不改变数据库的状态。这里有一个称为 executeQuery() 的相对应的方法,它的返回值是 ResultSet 对象,如列表 3 所示。

列表 3. 执行一个查询
String bar, beer ; float price ; ResultSet rs = stmt.executeQuery("SELECT * FROM Sells"); while ( rs.next() ) { bar = rs.getString("bar"); beer = rs.getString("beer"); price = rs.getFloat("price"); System.out.println(bar + " sells " + beer + " for " + price + " Dollars."); }

由于查询而产生的行集包含在变量 rs 中,该变量是 ResultSet 的一个实例。集合对于我们来说并没有太大用处,除非我们可以访问每一个行以及每一个行中的属性。ResultSet 提供了一个光标,可以用它依次访问每一个行。光标最初被设置在正好位于第一行之前的位置。每个方法调用都会导致光标向下一行移动,如果该行存在,则返回 true,或者如果没有剩余的行,则返回 false

我们可以使用适当类型的 getXXX() 来检索某一个行的属性。在前面的实例中,我们使用 getString()getFloat() 方法来访问列值。注意,我们提供了其值被期望用作方法的参数的列的名称;我们可以指定用列号来代替列名。检索到的第一列的列号为 1,第二列为 2,依次类推。

在使用 PreparedStatement 时,可以通过先前插入的参数值来执行查询,然后对它调用 executeQuery(),如下所示:

ResultSet rs = prepareUpdatePrice.executeQuery() ;

关于访问 ResultSet 的注释
JDBC 还提供一系列发现您在结果集中的位置的方法:getRow()isFirst()isBeforeFirst()isLast(),以及 isAfterLast()

这里还有一些使可滚动光标能够自由访问结果集中的任意行的方法。在默认情况下,光标只向前滚动,并且是只读的。在为 Connection 创建 Statement 时,可以将 ResultSet 的类型更改为更为灵活的可滚动或可更新模型,如下所示:

Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); ResultSet rs = stmt.executeQuery("SELECT * FROM Sells");

不同的类型选项: TYPE_FORWARD_ONLYTYPE_SCROLL_INSENSITIVETYPE_SCROLL_SENSITIVE 。可以通过使用 CONCUR_READ_ONLYCONCUR_UPDATABLE 选项来选择光标是只读的还是可更新的。对于默认光标,可以使用 rs.next() 向前滚动它。对于可滚动的光标,您有更多的选项,如下所示:

rs.absolute(3); // moves to the third retrieved row rs.previous(); // moves back one row in the retrieved result set rs.relative(2); // moves forward two rows in the retrieved result set rs.relative(-3); // moves back three rows in the retrieved result set

对于可滚动光标的工作方式,这里有更多的详细描述。尽管可滚动光标对于特定应用程序是有用的,但是它导致极大的性能损失,所以应该限制和谨慎使用。可以在 参考资料小节中找到关于可滚动 ResultSet 的更多信息。

在序列化中不存在与 JDBC 的 ResultSet 相对应的机制。序列化和 JDBC 观察底层的数据的角度不同。JDBC (通常)假定底层数据是关系型结构的;而序列化假定底层数据是一个对象图。两种技术的底层数据结构存在显著差异。JDBC 的 Set 结构并不能自然地映射到序列化的对象图结构,反之亦然。当通过使用序列化语义将一个 Java 对象持久化时,数据的底层结构变成了一个字节流,该字节流展示了已经序列化了的核心对象的各种内部对象之间的关联。

JDBC 中的 ResultSet 导航是从一个 Set 元素移动到其他元素的过程,而在对象序列化中,这是不可能的,因为序列化涉及到对象关联,而不是将一组行封装到一个实体集合中。因此,Java 对象序列化无法向您提供用这种方式访问数据单独某个部分的能力。

事务
JDBC 允许将 SQL 语句组合到单独一个事务中。因此,我们可以通过使用 JDBC 事务特性来确保 ACID 属性。

Connection 对象执行事务控制。当建立连接时,在默认情况下,连接是自动提交模式下。这意味着每个 SQL 语句自身都被看作是一个事务,并且一完成执行就会被提交。

可以用以下方法开启或关闭自动提交模式:

con.setAutoCommit(false) ; con.setAutoCommit(true) ;

一旦关闭了自动提交,除非通过调用 commit() 显式地告诉它提交语句,否则无法提交 SQL 语句(即,数据库将不会被持久地更新)。在提交之前的任何时间,我们都可以调用 rollback() 回滚事务,并恢复最近的提交值(在尝试更新之前)。

我们还可以设置期望的事务隔离等级。例如,我们可以将设置事务隔离等级为 TRANSACTION_READ_COMMITTED,这使得在提交值之前,不允许对它进行访问。并且禁止脏读。在 Connection 接口中为隔离等级提供了五个这样的值。默认情况下,隔离等级是可序列化的。JDBC 允许我们发现数据库所设置的是什么事务隔离等级(使用 ConnectiongetTransactionIsolation() 方法)以及设置适当的等级(使用 ConnectionsetTransactionIsolation() 方法)。

回滚通常与 Java 语言的异常处理能力结合在一起使用。这种结合为处理数据完整性提供一个简单高效的机制。在下一节中,我们将研究如何使用 JDBC 进行错误处理。

注意,Java 对象序列化并不直接支持事务管理。如果您正在使用序列化,则将需要借助其他的 API,例如 JTA,来获得这个效果。然而,为了获得事务隔离的效果,可以选择在执行一个更新操作时同步该序列化对象,如下所示:

Synchronized(my_deserialized_object) { //Perform the updates etc... }

利用异常处理错误
软件程序中总是出现一些错误。通常,数据库程序是关键性应用程序,而且适当地捕获和处理错误是有必要的。程序应该恢复并且让数据库处于某种一致的状态下。将回滚与 Java 异常处理程序结合使用是达到这种要求的一种简便方法。

访问服务器(数据库)的客户(程序)需要能够识别从服务器返回的所有错误。JDBC 通过提供两种等级的错误条件来访问这种信息:SQLExceptionSQLWarningSQLException 是 Java 异常,它(如果未被处理)将会终止该应用程序。SQLWarningSQLException 的子类,但是它们代表的是非致命错误或意想不到的条件,因此,可以忽略它们。

在 Java 代码中,希望抛出异常或者警告的语句包含于 try 块中。如果在 try 块中的语句抛出异常或者警告,那么可以在对应的某个 catch 语句中捕获它。每个捕获语句都指出了它准备捕获的异常。

换句话说,如果数据类型是正确的,但是数据库大小超出其空间限制并且不能建立一个新表,则可能会抛出一个异常。 可以从 ConnectionStatement,以及 ResultSet 对象中获取 SQLWarning。每个对象都只是存储最近 SQLWarning。因此,如果通过 Statement 对象执行其他语句,则将放弃所有早期的警告。列表 4 举例说明了 SQLWarning 的使用。

列表 4. 实际运行中的 SQLWarnings
ResultSet rs = stmt.executeQuery("SELECT bar FROM Sells") ; SQLWarning warn = stmt.getWarnings() ; if (warn != null) System.out.println("Message: " + warn.getMessage()) ; SQLWarning warning = rs.getWarnings() ; if (warning != null) warning = warning.getNextWarning() ; if (warning != null) System.out.println("Message: " + warn.getMessage()) ;

实际上,SQLWarning 在某种程度上比 SQLException 更为罕见。最常见的是 DataTruncation 警告,它表示在从数据库读或写数据时存在问题。

Java 并没有提供序列化所使用的特定的异常类。使用序列化时发生的大多数异常都与执行的 I/O 操作有关,因此,在这些情况中 I/O 异常类将满足要求。

批处理
JDBC 2.0 提供一个用于批处理的强大API。批处理允许积累一组 SQL 语句,并且将它们一起发送并处理。一个典型的批处理就是银行应用程序,该应用程序每隔一刻钟就要更新许多账号。在减少从 Java 代码到数据库的往返次数方面,批处理是一个强大功能。

Statement 接口提供 addBatch(String) 方法,将 SQL 语句添加到一个批处理中。一旦已经将所有的 SQL 语句都增加到该批处理中,就可以使用 executeBatch() 方法一起执行它们。

然后,用executeBatch() 方法执行 SQL 语句,并返回 int 值的一个数组。该数组包含受每条语句影响的行数。将 SELECT 语句或者其他返回 ResultSet 的 SQL 语句放在一个批处理中会导致 SQLException

列表 5 中列出了利用 java.sql.Statement 进行批处理的一个简单实例。

列表 5. 实际运行中的批处理
Statement stmt = conn.createStatement(); stmt.insert("DELETE FROM Users"); stmt.insert("INSERT INTO Users VALUES('rod', 37, 'circle')"); stmt.insert("INSERT INTO Users VALUES('jane', 33, 'triangle')"); stmt.insert("INSERT INTO Users VALUES('freddy', 29, 'square')"); int[] counts = stmt.executeBatch();

在您不知道特定语句将运行的次数时,批处理是一个处理 SQL 代码的好方法。例如,如果在不使用批处理的情况下试图插入 100 条记录,那么性能可能会受到影响。如果编写一个脚本,增加 10000 条记录,那么情况会变得更糟。添加批处理可以帮助提高性能,后者甚至能够提高代码的可读性。

Java 对象序列化并不支持批处理。通常,会在某个对象的范围(联系图)上运用序列化,在这种情况下,批处理没有意义。因此,批处理在数据更新的定时和分组方面为您提供一定的灵活性,而这些对于序列化来说不一定是可用的。

从 Java 代码调用存储过程
存储过程是一组 SQL 语句,它们建立了一个逻辑单元,并执行特定任务。可以用存储过程来封装一个操作或者查询的集合,这些操作或查询都将在一个数据库服务器上执行。存储过程是在数据库服务器中被编译和存储的。因此,每次调用存储过程时,DBMS 都将重用已编译的二进制代码,因此执行速度会更快。

JDBC 允许您从 Java 应用程序中调用数据库存储过程。第一步是创建 CallableStatement 对象。与 StatementPreparedStatement 对象一样,这项操作是用一个打开的 Connection 对象完成的。CallableStatement 对象包含对存储过程的调用;但它并不包含存储过程自身。列表 6 中的第一行代码使用 con 连接建立了对存储过程 SHOW_ACCOUNT 的调用。波形括号中括住的部分是存储过程的转义语法。当驱动程序遇到 {call SHOW_ACCOUNT} 时,它将该转义语法翻译成数据库所使用的本地 SQL,从而调用名为 SHOW_ACCOUNT 的存储过程。

列表 6. 实际运行中的存储过程
CallableStatement cs = con.prepareCall("{call SHOW_ACCOUNT(?)}"); cs.setInt(1,myaccountnumber); ResultSet rs = cs.executeQuery();

假设 Sybase 中的存储过程 SHOW_ACCOUNT 包含列表 7 中所示的代码。

Listing 7. SHOW_ACCOUNT stored procedure
CREATE PROCEDURE SHOW_ACCOUNT (@Acc int) AS BEGIN Select balance from USER_ACCOUNTS where Account_no = @Acc END

ResultSet rs 看起来类似于:

balance ---------------- 12000.95

注意,用来执行 cs 的方法是 executeQuery(),由于 cs 调用的存储过程只包含一个查询,所以只产生一个结果集。如果该过程只包含一个更新或者一个 DDL 语句,则将使用 executeUpdate() 方法。然而,有时候存在存储过程包含多个 SQL 语句的情况,在这种情况下,它将产生多个结果集、多个更新计数,或者结果集和更新计数的某种结合。因此,应该使用 execute() 方法执行 CallableStatement

CallableStatement 类是 PreparedStatement 的子类,因此 CallableStatement 对象可以接受与 PreparedStatement 对象相同的参数。而且,CallableStatement 对象可以接受输出参数,并将该参数用于输入和输出。INOUT 参数和 execute() 方法通常很少使用。要想处理 OUT 参数,需要通过使用 registerOutParameter(int, int) 方法将 OUT 参数注册到存储过程。

举例说明,我们假设 GET_ACCOUNT 过程包含列表 8 中的代码。

列表 8. GET_ACCOUNT
CREATE PROCEDURE GET_ACCOUNT (@Acc int, @balance float OUTPUT) AS BEGIN Select @balance = balance from USER_ACCOUNTS where Account_no = @Acc END

在这个实例中,参数 balance 被声明是一个 OUT 参数。现在,调用该过程的 JDBC 代码如列表 9 所示。

列表 9. 调用一个存储过程的 JDBC 代码
CallableStatement csmt = con.prepareCall("{GET_ACCOUNT(?,?)"); csmt.setInt(1,youraccountnumber); csmt.registerOutParamter(2,java.sql.Types.FLOAT); csmt.execute();

正使用 Java 序列化时,并不需要访问任何外部的系统,如 DBMS。换句话说,序列化是一个纯 Java 语言现象,它不涉及执行一个外部环境中的已编译代码。因此,在序列化中不存在与 CallableStatement 对象相对应的机制。这意味着您不能将数据处理转移到外部系统或者组件中,尽管这些系统或者组件可能更适合它。

包装
在读完本文之后,我们希望您赞同:对于数据管理和持久化而言, JDBC 是比 Java 对象序列化要好得多的方法。

JDBC 是一个用来访问数据存储的极好的 API。 JDBC 最好的东西是它提供单一的 API 集合来访问多种数据源。用户只需要学习一个 API 集合,就可以访问任何数据源,这些数据源可以是关系型的、层次型的或者任何其他格式。您需要的只是一个 JDBC 驱动程序,用它连接到目标数据源。JDBC 做了大量工作,将所有技术细节都封装到了一个实现软件包中,从而将程序员从供应商特定的桎梏中解放出来。

表 1 对比了 JDBC 和 Java 对象序列化的各种特性。

表 1. JDBC 对 Java 序列化
对象序列化 JDBC
数据管理 使用文件系统存储序列化对象格式。这些系统中不包括特定的数据管理系统。序列化对象(存储在普通文件中的)通常是以自己的特殊方式通过底层 OS 来管理的。 使用一个 EAI/数据库来存储数据。EAI 或者数据库具有一个用来管理数据源中的数据指定的数据库管理系统(DBMS)。JDBC 是将请求发送到 DBMS 的 JVM 和 DBMS 之间的接口。JDBC 自身并不具有任何数据管理功能。
数据结构 底层的数据结构是一个对象图。序列化将 Java 对象的状态写入到文件系统。 底层的数据结构可以是关系型的、层次型的,或者是网络形状。但是数据的逻辑视图通常是一个表。
数据定义 数据定义涉及到使用序列化语义建立一个可序列化对象并持久化该对象。 数据定义涉及到在目标数据存储中建立必要的表,并且提供实体集之间的域级关系的明确定义。这一般是通过使用目标 DBMS 所提供的软件来完成的。
数据检索 数据检索涉及反序列化对象,并使用访问者方法读取对象的属性。 DBMS 提供一个特殊的数据子语言来检索数据。通过 JDBC API 可以将以这种数据子语言编写的语句传递给目标数据源。DBMS 负责验证、执行和返回该语句的结果。
安全 没有可以使用的定义良好的安全机制。然而,底层的 OS 可以提供已序列化文件的安全。 DBMS 提供一个广泛的安全特性集合。它可以完成认证和授权的工作。在可以访问或者操作 DBMS 上的数据之前,JDBC API 需要给目标 DBMS发送证书。
事务 没有可以使用的特定的事务控制机制。通过使用其他的 J2EE API,例如 JTA 或者 JTS,可以在程序上维护事务。 DBMS 提供复杂的事务管理。JDBC API 提供有用的方法来提交和回滚事务。
并发控制 没有可以使用的特定的并发控制机制。不过,通过使用 Java 语言中的同步技术可以获得并发控制的效果。 DBMS 提供多种等级的事务隔离。可以使用 JDBC API 方法来选择一个特定等级的隔离。

Java 对象序列化和 JDBC 是 Java 技术领域中许多数据持久化机制中的两种。在需要在多个 JVM 之间以 Java 语言特定格式共享数据(例如用 RMI 的按值传递机制共享数据)时,序列化最适合不过。然而,Java 序列化并不适用于企业数据,需要以一种定义良好的结构对这些数据进行组织。在这样的企业系统中,需要在多个系统和子系统之间共享数据,而这些系统并不一定都与 Java 语言兼容。在这种情况中,对象序列化根本不能工作。

JDBC 提供一个公用 API来访问异构的数据存储。它是 JVM 和目标 DBMS 之间的粘合剂。它提供了一个使用 Java 平台访问数据存储和维护企业数据的纲领性方法。然而,执行 CRUD 操作所需的所有代码都是由开发人员编写。

为了在企业环境中最有效地使用 JDBC,架构设计人员需要分析其企业中的数据,并开发一个用于数据持久性的框架。由于使用 JDBC 持久化数据的机制与系统想要解决的商业问题无关,因此强烈建议将数据持久性层与应用程序的商业逻辑相分离。设计模式对设计这种框架非常有帮助。

参考资料

作者简介
G.V.B. Subrahmanyam 博士拥有技术领域的硕士学位和 IIT Kharagpur 授予的博士学位,还有 BITS, Pilani 授予的软件系统硕士学位。可以通过 Subrahmanyam.vb.gampa@citigroup.com 联系他。


Shankar Itchapurapu 拥有计算机应用方面的硕士学位。可以通过 shankar.i@polaris.co.in 联系他。

【转载】Looking into the Tiger's eye Looking into the Tiger's eye

Ed Ort
June 28, 2004

Great Stuff Here Now -- More Coming Soon

There's a lot of great new stuff in the Java technology platform today, and even more is on the way. That's the clear message that the chief architects of the Java platform, Sun V.P. and Fellow, Graham Hamilton, and Sun Distinguished Engineers Tim Lindholm and Bill Shannon, delivered to an extremely large and enthusiastic audience in their technical general session "Java Platform Update--Roadmap & Big Directions." So what's this great new stuff?

Here's a summary:

  • Java 2 Platform, Standard Edition (J2SE) Version 5.0 (code name "Tiger"). This new release of the Java platform includes a very large number (almost 100) of Java Specification Requests (JSRs) and other updates designed to improve ease of development, speed performance, and extend monitoring and management capabilities. Even core XML support has been enhanced. If you're wondering why Tiger is J2SE "5.0" instead of the traditional J2SE "1.x", Hamilton noted that "because J2SE 5.0 is our biggest update to the platform since the original 1.0, it felt kind of stupid that we were still calling things 1.1, 1.2, ... And with a big roaring Tiger, we wanted to change the numbering system, so we're now going to use the 5.0 number for J2SE, and similarly Jave 2 Platform, Enterprise Edition (J2EE) is going to move to 5.0. Future releases will be 6.0 and 7.0."

    To underscore how many changes are incorporated into the Tiger release, Hamilton included a slide that was literally covered with new and enhanced features. Tiger is currently available as a Beta 2 release. A Release Candidate is targeted for August and the final release should be available on September 30th.

    To help introduce the Tiger release, an eight-week old tiger cub named "Java" joined Hamilton on stage. Hamilton said that "we chose the name Tiger for the J2SE 5.0 release because tigers are totally wonderful. We also wanted to give the impression of strength, power, and maybe a little fierceness." Perhaps more cute than fierce, Java (the tiger cub), still made a big impact.

  • J2SE 6.0 (code name "Mustang") and J2SE 7.0 (code name "Dolphin"). These releases are currently in the planning stage. Mustang is scheduled for availability in early 2006, Dolphin in mid-to-late 2007. These releases will make even more advances into ease of development, monitoring and management, and XML and web services.
  • Java 2 Platform, Micro Edition (J2ME). There's a lot of focus here on providing common services for wireless devices (valuable for games and text messaging), supporting enterprise (rich data) services, and in easing device development and customization. Lindholm highlighted a number of the many JSRs that are being incorporated into J2ME. These JSRs cover a wide swath of territory that includes web services, security and trust services, and scalable vector graphics. JTWI (the low-end wireless stack) is also an area that bears watching. Lindholm asked the audience to keep an eye out for the next release of JTWI and be vocal as far as feedback.
  • Java 2 Platform, Enterprise Edition (J2EE) is a very powerful platform, but Shannon conceded that J2EE is difficult to get started. "Even simple applications need a lot of boilerplate code." So the question the J2EE team asked was "Can we keep the power of J2EE, but make more typical development tasks simpler?" Shannon said that the group thinks they can, and that's the focus of J2EE 5.0. Targeted for the second half of 2005, J2EE 5.0 puts heavy emphasis on ease of development. One of the J2EE technologies where this will be readily apparent is Enterprise JavaBeans technology. As an example, Shannon showed the code for a sample session bean and compared it to what it would look like in J2EE 5.0. Thirteen lines of code dropped to five -- and shorter lines at that. Shannon said that the intent is to "remove boilerplate code, rely on defaults whenever possible, and drastically reduce the need for deployment descriptors." The plan for reduced reliance on deployment descriptors leverages class annotations (a new feature in J2SE 5.0).

Key Themes: Quality, Ease of Development, Monitoring and Manageability

Quality is a recurrent theme in all these efforts. Hamilton said that the number one theme for Tiger is quality, as evidenced by stability, robustness, and compatibility. "We want all of your existing applications to work on top of Tiger." Hamilton also mentioned that the follow-on releases, Mustang and Dolphin, will carry on the quality theme "our goal is to ship no release before it's time."

The ease-of development goal in Tiger impelled the largest set of language updates in the history of Java technology releases since 1995. Some of these changes include:

  • Generic types, which allow developers to declare the type of a collection
  • Typesafe enums, which provide support for enumerated types
  • Enhanced for loops, which allow developers to iterate over collections and arrays without using iterators or index variables
  • varargs, which allow multiple arguments to be passed as parameters to methods
  • annotations, which allow developers to associate additional information (metadata) with classes interfaces, methods, and fields

As pointed out earlier, annotations will make it possible to meet goals, such as drastically reducing the need for J2EE technology-based application developers to write deployment descriptors. Tools will be able to build deployment descriptors based on annotations (and any deployment descriptors optionally provided by deployers). Ease of development will show up in fewer and simpler lines of code. This is not only true for enterprise beans, but for perhaps more pedestrian things such as database queries. Imagine annotations being leveraged to simplify SQL query creation.

Hamilton said that language changes will continue to be made in the Mustang and Dolphin releases, that is, with careful thought and review.

Monitoring and management is another key area of emphasis. Hamilton said that "as people are deploying very large applications, they need to be able to track what's going on inside the application and find out what's happening at the JVM level and at the application level." To meet this need, a number of APIs have been added to monitor things at the VM level. In addition, Java Management Extensions (JMX), which has been a part of the J2EE platform, is now incorporated into the J2SE technology core. The JMX API allows developers to publish management agents ("mBeans") that can be used to monitor and manage applications. The platform also includes tools that make use of these monitoring and management facilities. One of these is a simple GUI-based tool called jconsole that can be used to monitor the VM. It also provides a generic API that can be used to monitor mBeans.

The Desktop Gets Some New Look and Feels

The desktop continues to be an important component of the Java platform. This is evidenced by performance improvements such as faster startup. It's also evidenced by some new and enhanced look and feels. One of these advances the old standard Java technology look and feel called Metal. Hamilton called the new L&F, named Ocean, a more gentle and less intrusive theme than Metal. Some other L&F changes include an enhanced Gnome GTK and an enhanced Aqua L&F for Mac users.

There are a number of other "forward-looking" ideas that are being worked on regarding the Java technology desktop. Two of these efforts are the aptly named JDesktop (JDIC), which provides components for desktop integration, and Java Desktop Network Components (JDNC), which provides high-level, data-aware components. Hamilton called on Sun engineer, Chet Haase, to demonstrate an application that takes advantage of JDIC. Among other things he showed, Haase demonstrated some of the cool navigation assists that JDIC offers. Significantly, the demo ran on Microsoft's upcoming OS release, Longhorn.

XML and Web Services Also in View

Hamilton noted that Tiger enhances some of the core J2SE XML support. This includes support for DOM Level 3, W3C Schema, XPath, an upgraded XSLT engine, and JAXP 1.3. Support for web services will be folded into J2SE in Mustang and Dolphin. This incudes support for JAX-RPC 2.0 client, JAXB 2.0 data binding, lightweight JAX-RPC services, XML encryption, and XML digital signatures.

Call to Action

Hamilton ended the presentation with a call to action. He encouraged the audience to:

  • Take advantage of the massive deployment already happening with J2ME and MIDP technologies.
  • Try out the Beta 2 release of Tiger. "Let us know of any urgent issues. Get ready for the full release in the fall."
  • Get the J2EE 1.4 SDK, which is available now and supports production deployment.
  • Participate in the JCP and public reviews for Mustang, Dolphin, and J2EE 5.0.

The "bottom line" is that a lot of good stuff is coming very soon, and some really cool stuff is coming later. So be active, try the new stuff out, and give feedback.

【转载】Sun Open Sources "Looking Glass" and Java 3D
Sun Open Sources "Looking Glass" and Java 3D
Summary
Sun Microsystems today underscored its commitment to open source and desktop technology leadership by contributing Project Looking Glass and Java 3D technology to the open source community. This contribution will unleash a new dimension of developer innovation by making Sun's technology available at Sun's 3D Desktop Technology Open Source Project on java.net.

Sun Microsystems today underscored its commitment to open source and desktop technology leadership by contributing Project Looking Glass and Java 3D technology to the open source community. This contribution will unleash a new dimension of developer innovation by making Sun's technology available at Sun's 3D Desktop Technology Open Source Project on java.net.

Sun also announced additional open source desktop efforts in collaboration with the Java developer community: the JDesktop Network Components (JDNC) and JDesktop Integration Components (JDIC). JDNC radically simplifies the development of rich networked desktop applications. JDIC seamlessly integrates cross-platform Java technology-based applications with the native desktop. These open source community contributions aim to promote innovation, ease of development, integration and interactivity on the desktop, and stimulate growth of the Java platform economy for all participants.

Project Looking Glass

Project Looking Glass is the 3D desktop project that first captivated the technology industry and blew the lid off the traditional windowing paradigm at its first mass demo in Summer 2003. Project Looking Glass' innovative desktop interface offers an intuitive, new 3D environment to interact with desktop applications featuring window transparency, rotation, zoom, multiple desktop workspaces and miniaturization. The technology helps developers build highly visual 3D desktops and applications that will run on the Solaris Operating System (OS) and Linux systems such as Sun's Java Desktop System. The Project Looking Glass developer's release is expected to enable Java technology developers to break new ground in the way information and data is represented to the user.

The following features are now available in the Project Looking Glass developer's release:

  • 3D Window Manager Platform - Highly scalable Java 3D Application Programming Interface (API) with client-server model support that helps developers with design documents, initial specification and prototype implementation.
  • 3D Window Manager and Application Development API - Java API to enable development of new 3D desktop applications and 3D Window Manager features for the Project Looking Glass platform.
  • Native Application Integration Module - Module to run X11 applications within the 3D environment.
  • Sample 3D Window Manager - Sample implementation for testing and demonstration purposes.
  • 3D Environment Lite - Stand alone, simplified 3D environment for development and testing that can be run on any Java 3D API-enabled platform including Linux and the Solaris OS.

    For more information on Project Looking Glass, visit www.sun.com/software/project-looking-glass.

    Java 3D - Taking Java Technology to New Dimensions

    Sun is also releasing the Java 3D API to the open source community on java.net. The Java 3D API, recently used by NASA for its command and control system for the Mars Rover mission, helps developers incorporate high-quality, scalable, platform-independent 3D graphics into applications and applets based on Java technology. To access Java 3D, visit java.sun.com/products/java-media/3D/.

    JDesktop Integration Components (JDIC)

    The JDIC project, launched on java.net, will continue Java technology's focus on seamless desktop integration. It complements the native look and feel for Windows XP and GTK introduced in Java 2 Standard Edition (J2SE) 1.4.2 and the desktop integration enhancements in J2SE 5.0. JDIC will help developers create applications that run on multiple operating systems while giving users a quality user experience consistent with their desktop. Visit http://jdic.dev.java.net for more details.

    JDesktop Network Components (JDNC)

    JDNC aims to simplify the development of rich networked desktop applications. It offers a set of high-level user interface components with built-in networking and data-binding support that can be configured via XML. JDNC will lower the bar for rich client development and boost developer productivity, enabling a larger portion of developers to take advantage of highly interactive client applications. More information can be found at http://jdnc.dev.java.net.

    Project Looking Glass, Java 3D, JDIC, and JDNC projects are part of javadesktop.org, the java.net community for desktop developers. The 2004 JavaOne Developer Conference marks the first anniversary of java.net, the source for Java technology collaboration sponsored by Sun. In addition, java.net today launched a new community dedicated to the discussion, development and collaboration of Java Specification Requests (JSR) proposed by Java Community Process (JCP) members. This new community aims to increase efficiency by making it easier to set up JSR projects and providing the appropriate tools needed to communicate and share code with the community for greater transparency. For more information on the JavaOne conference, visit http://java.sun.com/javaone.


  • read Story
    email this Story
    print this Story
    read and leave feedback
    About the author
    JDJ News Desk monitors the world of Java to present IT professionals with updates on technology advances, business trends, new products and standards in the Java and i-Technology space. (more)

    第1页,共1页