# 第 11 章　使用对象-关系映射持久化数据

本章内容：

* 使用 Spring 和 Hibernate
* 借助上下文 Session，编写不依赖于 Spring 的 Repository
* 通过 Spring 使用 JPA
* 借助 Spring Data 实现自动化的 JPA Repository

小时候，骑自行车是一件很有趣的事情，对吧？在清晨，我们骑车上学。放学后，我们游逛到朋友家。当天色渐晚之时，在父母的呼喊声中，我们骑车回家。那些日子真的很有意思！

后来，随着慢慢长大，现在我们所需要的不仅仅是一辆自行车了。有时，我们需要走很远的路去上班或需要装载一些生活用品，还有可能接送孩子去上足球课。如果生活在得克萨斯州的话，我们还必须需要一台空调。我们的需求超出了自行车的功能范围。

在数据持久化的世界中，JDBC 就像自行车。对于份内的工作，它能很好地完成并且在一些特定的场景下表现出色。但随着应用程序变得越来越复杂，对持久化的需求也变得更复杂。我们需要将对象的属性映射到数据库的列上，并且需要自动生成语句和查询，这样我们就能从无休止的问号字符串中解脱出来。此外，我们还需要一些更复杂的特性：

* 延迟加载（_Lazy loading_）：随着我们的对象关系变得越来越复杂，有时候我们并不希望立即获取完整的对象间关系。举一个典型的例子，假设我们在查询一组 PurchaseOrder 对象，而每个对象中都包含一个 LineItem 对象集合。如果我们只关心 PurchaseOrder 的属性，那查询出 LineItem 的数据就毫无意义。而且这可能是开销很大的操作。延迟加载允许我们只在需要的时候获取数据。
* 预先抓取（_Eager fetching_）：这与延迟加载是相对的。借助于预先抓取，我们可以使用一个查询获取完整的关联对象。如果我们需要 PurchaseOrder 及其关联的 LineItem 对象，预先抓取的功能可以在一个操作中将它们全部从数据库中取出来，节省了多次查询的成本。
* 级联（_Cascading_）：有时，更改数据库中的表会同时修改其他表。回到我们订购单的例子中，当删除 Order 对象时，我们希望同时在数据库中删除关联的 LineItem。

一些可用的框架提供了这样的服务，这些服务的通用名称是对象/关系映射（object-relational mapping，ORM）。在持久层使用 ORM 工 具，可以节省数千行的代码和大量的开发时间。ORM 工具能够把你的注意力从容易出错的 SQL 代码转向如何实现应用程序的真正需求。

Spring 对多个持久化框架都提供了支持，包括Hibernate、iBATIS、Java 数据对象（Java Data Objects，JDO）以及 Java 持久化 API（Java Persistence API，JPA）。与 Spring 对 JDBC 的支持那样，Spring 对 ORM 框架的支持提供了与这些框架的集成点以及一些附加的服务：

* 支持集成 Spring 声明式事务；
* 透明的异常处理；
* 线程安全的、轻量级的模板类；
* DAO 支持类；
* 资源管理。

本章没有足够的篇幅介绍 Spring 支持的全部 ORM 框架。其实这并不会有什么问题，因为 Spring 对不同 ORM 解决方案的支持是很相似的。一旦掌握了 Spring 对某种 ORM 框架的支持后，你可以轻松地切换到另一个框架。

在本章中，我们将会看到 Spring 如何与最常用的两种 ORM 方案集成：Hibernate 和 JPA。同时还会通过 Spring Data JPA 了解一下 Spring Data 项目。借助这种方式，我们不仅可以学习到如何借助 Spring Data JPA 移除 JPA Repository 中的样板式代码，还能为下一章的如何将 Spring Data 用于无模式的存储打下基础。

让我们先来看看 Spring 是如何为 Hibernate 提供支持的。
