1、1什么是持久化几乎所有的应用程序都需要持久化数据。持久化在应用程序开发中是基本概念之一。如果一个信息系统在断电时没有保存数据,这个系统就没有什么实用价值了。当我们在 Java 中谈到持久化时,一般是指利用 SQL 在关系数据库中存储数据。我们先简单地看看这项技术,以及如何在Java 中使用它。有了这个信息基础,再接着讨论持久化,以及如何在面向对象的应用程序中实现它。1 关系数据库就像大部分其他的开发人员一样,你可能已经使用过关系数据库。我们大部分人每天都在使用关系数据库。关系技术是个已知数,仅此一点就成为许多组织选择它的一个充分理由。但是只提这一点有些贬低了它应得的尊重。关系数据库的地位如此根
2、深蒂固,是因为它们是一种出奇灵活和稳健的数据管理方法。由于关系数据模型完整且一致的理论基础,关系数据库可以有效保证和保护数据的完整性,这是它众多的优良特性之一。有些人甚至会说计算领域的最后一项大发明就是用于数据管理的关系概念,它由 E.F Codd(Codd,1970)于 30 多年前首先提出。关系数据库管理系统既不特定于 Java,也不是一种特定于某个特殊应用程序的关系数据库。这个重要的原理就是数据独立(data independence) 。换句话说,我们无法充分强调这个重要的事实:数据比任何应用程序都存在得更长久。关系技术提供了一种在不同应用程序或者构成同一应用程序(例如事务引擎和报告引
3、擎)的不同技术之间共享数据的方式。关系技术是许多异构的系统和技术平台的一个共同特性。因此,关系型数据模型经常是业务实体常用的企业级表示法。关系数据库管理系统具有基于 SQL 的应用编程接口(Application Programming Interface ,API) ;因此,我们称当今的关系数据库产品为 SQL 数据库管理系统(database management system) ,或者当我们谈到特定系统时,称之为 SQL 数据库(database) 。在更详细地探讨 SQL 数据库应用程序方面之前,必须提到一个重要的问题:虽然有些产品也作为关系数据库销售,但是只提供 SQL 数据语言接口
4、的数据库系统并不是真正的关系数据库,并且在很多方面甚至与原始概念相去甚远。自然,这样就导致了混乱。SQL 从业者抱怨关系型数据模型在 SQL 语言方面的不足,而关系型数据管理专家则报怨 SQL 标准在关系模型和理念方面实现得不够。应用程序开发人员被夹在其中,承受着传送一些有效东西的压力。我们将在本书中始终强调有关这个问题的一些重要而有意义的方面,但是通常关注应用程序方面的。2 理解 SQL要有效地使用 Hibernate,扎实地理解关系模型和 SQL 是前提条件。你需要理解关系模型,以及像保证数据完整性的标准化这样的话题,还要利用你的 SQL 知识调优 Hibernate 应用程序的性能。Hi
5、bernate 让许多重复的编码任务自动化,但是如果要利用现代 SQL 数据库的全部功能,你的持久化技术必须扩充至超越 Hibernate 本身。记住,根本的目标是稳健、高效的持久化数据管理。2回顾一些本书中用到的 SQL 术语。你用 SQL 作为数据定义语言(Data Definition Language,DDL) ,用 CREATE 和 ALTER 语句创建数据库 Schema。创建了表(和索引、序列等)之后,又用 SQL 作为数据操作语言(Data Manipulation Language,DML)来操作和获取数据。操作数据的操作包括插入(insertion) 、更新(update)
6、和删除(deletion) 。通过限制(restriction) 、投影(projection)和联结(join)操作(包括笛卡儿积,Cartesian product)执行查询来获取数据。为了有效地生成报表,可视需要使用 SQL 对数据进行分组(group) 、排序(order)和统计(aggregate) 。甚至可以相互嵌套 SQL 语句;这种技术使用了子查询(subselect) 。你可能已经使用 SQL 多年,熟悉这门语言的基本操作和语句编写。但我们从自身的经验中知道,有时候 SQL 仍然难以记住,而且一些术语的用法也很不同。要理解这本书,我们必须使用相同的术语和概念,因此如果我们提到
7、的有些术语对你来说是陌生的或者不够清楚,建议你读一下附录 A。如果需要更多的资料,尤其是有关任何性能方面和 SQL 如何执行的,去找一本 Dan Tow 在2003 年出版的优秀著作 SQL Tuning。也看看 Chris Date 在 2003 年出版的著作 An Introduction to Database Systems,了解(关系)数据库系统的理论、概念和思想。对于你在数据库和数据管理方面可能遇到的所有问题,后者是一本极好的参考书。虽然关系数据库是 ORM 的一部分,但是,另一部分却由 Java 应用程序中的对象组成,它们需要用 SQL 持久化到数据库中和从数据库中加载。3 在
8、Java 中使用 SQL在 Java 应用程序中使用 SQL 数据库时,Java 代码通过 Java 数据库连通性(Java DataBase Connectivity,JDBC)API 把 SQL 语句发到数据库。无论是手工编写 SQL 并嵌入到 Java 代码里面,还是由 Java 代码在运行中生成,都要用 JDBC API 绑定实参,来准备查询参数、执行查询、滚动查询结果表、从结果集中获取值,等等。这些都是底层的数据访问任务;作为应用程序开发人员,我们更关注需要这些数据访问的业务问题。我们真正想编写的是把对象的代码类的实例保存和获取到数据库,或者从数据库获取,使我们从这类底层的苦差事中解
9、脱出来。由于数据访问任务通常很单调乏味,我们不禁要问:关系型数据模型和(特别是)SQL 都适合面向对象应用程序中的持久化吗?我们立即回答:是的!SQL 数据库支配了计算行业有许多原因关系数据库管理系统是唯一公认的数据管理技术,并且它们通常是任何 Java 项目的必要条件(requirement) 。然而,在过去的 15 年里,开发人员一直在谈论范式不匹配的问题。这种不匹配解释了为什么都要在每一个企业项目中与持久化相关的问题上付出如此巨大的努力。这里所说的范式(paradigm)是指对象模型和关系模型,或者可能是面向对象编程(Object-Oriented Programming,OOP)和 S
10、QL。让我们通过询问在面向对象的应用程序开发环境中,持久化意味着什么,来开始对不匹配问题的探讨。首先,把本节开头所述的过分简化的持久化定义,扩展为在维护和使用持久化数据中3对所涉及内容的一个更广泛、更成熟的理解。4 面向对象应用程序中的持久化在面向对象的应用程序中,持久化允许一个对象在创建之后依然存在。对象的这种状态可以被保存到磁盘,且相同状态的对象可以在未来的某个时候被重新创建。这并非只限于单独的对象整个关联对象网络也可以被持久化,且以后在一个新的进程中被重新创建。大多数对象并不是持化久的;瞬时(transient)对象的生命周期有限,由实例化它的进程的寿命所决定。几乎所有的 Java 应用
11、程序都混合包含了持久对象和瞬时对象;因此,我们需要一个子系统来管理持久化数据。现代的关系数据库为持久化数据提供了一个结构化的表示法,能够对数据进行操作、排序、搜索和统计。数据库管理系统负责管理并发性和数据的完整性;它们负责在多用户和多应用程序之间共享数据。它们通过已经利用约束实现的完整性规则来保证数据的完整性。数据库管理系统提供数据级的安全性。当我们在本书中讨论持久化时,考虑以下这些事情:结构化数据的储存、组织和获取;并发性和数据完整性;数据共享。特别是,我们正在使用领域模型的面向对象的应用程序环境中考虑这些问题。使用领域模型的应用程序并不直接使用业务实体的表格式表示法;该应用程序有它自己的业
12、务实体的面向对象模型。例如,如果一个在线拍卖系统的数据库有 ITEM 和 BID 表,Java 应用程序就会定义 Item 和 Bid 类。然后,业务逻辑并不直接在 SQL 结果集的行和列上进行工作,而是与这个面向对象的领域模型及其作为关联对象网络的运行时实现进行交互。Bid 的每个实例都引用一个拍卖 Item,而且每个 Item 都可以有一个对 Bid 实例的引用集合。业务逻辑并不在数据库中执行(作为 SQL 存储过程);而是在应用层的 Java 中实现的。这就允许业务逻辑使用高级的面向对象的概念,例如继承和多态。比如,我们可以使用众所周知的设计模式,如 Strategy(策略) 、Medi
13、ator(中介者)和Composite(组合) (Gamma 等,1995) ,所有这些模式都依赖于多态的方法调用。现在给你一个警告:并非所有的 Java 应用程序都以这种方式设计,它们也不应该只以这种方式设计。简单的应用程序不用领域模型可能更好。复杂的应用程序可能必须重用现有的存储过程。SQL 和 JDBC API 对于纯表格式数据的处理堪称完美,并且 JDBC 的行集合(RowSet)使 CRUD 操作变得更容易了。使用持久化数据的表格式表示法很直接且易于理解。然而,对于含有重要业务逻辑的应用程序来说,领域模型方法帮助明显改善代码的可重用性和可维护性。实际上,这两种策略都是常用和必需的。许
14、多应用程序都需要执行修改大组数据、接近数据的过程。同时,在应用层中执行一般在线事务处理逻辑的面向对象的领域模型时,其他的应用程序模块可以从中受益。你需要一种有效地把持久化数据带近应用程序代码的方法。如果我们再次考虑 SQL 和关系数据库,最终会发现两种范式之间的不匹配。SQL 操作如投影和联结始终会导致结果数据的表格式表示法。 这就是传递闭包(transitive closure) ,关联操作的结果也始终是一种关联。 这与 Java 应用程序中用来执行业务逻辑的关联对象网络大不相同。4这些是根本不同的模型,而不只是把同一模型形象化的不同方式。带着这些认识,就可以开始看一些问题了有些已经十分了解,有些则还不太了解必须通过一个结合了这两种数据表示法的应用程序来解决:一个面向对象的领域模型和一个持久化的关系模型。让我们深入探讨一下所谓的范式不匹配。