J2EE 应用程序中的数据管理和数据持久性
2008-01-05 10:33:50 来源:WEB开发网核心提示:本文分析了在 java 平台上可用的两个数据治理策略:Java 对象序列化和 Java 数据库连接(JDBC),尽管本质上这两种数据治理策略并不存在孰优孰劣的问题,J2EE 应用程序中的数据管理和数据持久性,但在治理企业信息系统时,JDBC 轻而易举地得以胜出,每次使用相同的 SQL 语句都需要重新编译一次,还可以通过
本文分析了在 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(<your driver class Name>);
Java.sql.Connection conn = DriverManager.getConnection(<connection URL>);
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 语句。
Prepa
更多精彩
赞助商链接