Hibernate简介
时间:2010-08-29 来源:静夜独思
大多数有一定规模的开发项目都涉及关系数据库。多数商业应用程序的核心是大型的有序信息存储库,比如编目、顾客列表、合同详细信息、出版的文章和建筑设计方案。
由于万维网的出现,对数据库的需求增长了。在线书店和在线报纸的顾客都要使用数据库,尽管他们可能不会意识到这一点。而实际上,在应用程序内部会查询数据库并提供响应。
Hibernate这样的对象-关系映射(Object-Relational Mapping,ORM)适合一部分解决方案,而对于其他情况,通过JDBC(Java Database Connectivity)API直接访问数据的传统方式可能更合适。我们认为Hibernate是很好的首选方式,因为使用他并不妨碍同时使用其他方式。
1.1 POJO
在理想环境中,获得任何Java对象并将它持久化到数据库中都应该是很轻松的。不需要为此编写特殊的代码,也不会有性能损失,而结果是完全可移植的。
没有特殊情况发生,不需要为类与数据库表的关联做任何额外的工作,也没有性能问题。
Hibernate已经非常接近这个理想目标了,至少与其他替代方式相比已经很方便了,但还是需要创建配置文件,而且要考虑微妙的性能问题。但无论如何,Hibernate实现了它的基本目标——使我们能够在数据库中存储POJO(Plain Old Java Object,普通Java对象)。图 1说明了Hibernate如何在客户机代码和数据库之间起到桥梁的作用。
图 1:Hibernate在Java应用程序中的角色
表示传统Java对象的直接持久化的常用术语是对象-关系映射——也就是说,将Java中的对象映射到数据库中的关系实体。
POJO可以是任何Java对象。Hibernate使我们能够对POJO进行持久化,而受到的限制却非常少。下面是一个简单的POJO示例,它代表一个消息。
/** * filename: Message.java */ package sample.entity; /** * @author: Sheldon Chen * @Date: 2010-8-28 * @Time: 下午06:25:59 * */ public class Message { private int id; private String message; public Message(String message) { this.message = message; } Message() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
在这里,Hibernate需要的唯一东西是一个私有的默认构造器。Hibernate要求被存储的所有POJO都要提供一个默认构造器。但是,即使第三方类无法满足这个小小的要求,也是有其他解决方法的。
1.2 Hibernate和对象-关系映射的起源
如果Hibernate是一种解决方案,那么它所要解决的问题是什么呢?其一便是希望简化对象持久化的编程。这是因为在使用JDBC时需要编写相当多的代码,并且要仔细考虑各种规则(比如进行连接管理的那些规则),从而确保应用程序不会造成资源泄漏。即使在知道正确的消息标识符的情况下,用数据库中的数据填充下面的Motd对象也需要大量代码。
1.2.1 Hibernate作为持久化解决方案
Hibernate可以解决上述的许多问题,或者缓解某些问题,所以我们依次讨论Hibernate对这些问题的影响。
Hibernate不要求开发人员将POJO一一映射到表。可以由多个表列构造出一个POJO,也可以将几个POJO持久化到同一个表中。
Hibernate直接支持类之间的继承关系和各种其他关系。
尽管在Hibernate启动和处理配置文件阶段有一些性能开销,但总的来说,Hibernate被认为是一种很快速的工具。性能问题很难量化,对待所有性能问题,你都应该进行测试。而不是仅根据舆论趋势做出选择。
在Hibernate中,可以在部署时指定映射,但这不是必须的。Hibernate方式致力于减少在新环境中部署应用程序的代价。
Hibernate使用的POJO可以非常轻松自然地实现泛化,从而在其他应用程序中使用。对于Hibernate库没有直接的依赖性,所以POJO可以放进不需要持久化的环境中,也可以使用任何其他的“对POJO友好的”机制对它们进行持久化。
在处理可序列化POJO方面,Hibernate没有任何问题。
有许许多多现有的代码。任何能够持久化到数据库中的Java对象都适合进行Hibernate持久化。因此,Hibernate很自然地成为专用解决方案的替代品,也可以作为还没有集成数据库持久化功能的应用程序的持久化引擎。因此,通过选用Hibernate持久化,就不必亲自为应用程序中的业务对象做出任何特殊的设计决定。
1.3 Hibernate Hello World示例
/** * filename: ListMessages.java */ package sample; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import sample.entity.Message; /** * 消息应用程序. * * @author: Sheldon Chen * @Date: 2010-8-28 * @Time: 下午06:33:21 * */ public class ListMessages { @SuppressWarnings("unchecked") public static void main(String[] args) { SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); List<Message> messages = session.createQuery("FROM Message").list(); for (Message message : messages) { System.out.println(message.getMessage()); } session.close(); sessionFactory.close(); } }
一些额外的代码提供了JDBC示例不具备的功能(尤其是事务处理和缓存)。
1.4 映射
Hibernate需要有某个东西告诉它,哪些表与哪些对象相关(这一信息常常在一个XML映射文件中提供)。对于希望映射到数据库中的每个POJO,只需创建并关联一个短小简洁的映射文件。如果愿意的话,也可以使用一个单一配置文件,但这不是必须的,也不鼓励这样做。
为Hibernate的所有配置文件提供了一个DTD,所以在使用出色的XML编辑器创建配置文件时,应该能够利用文件的自动补全和自动检验功能。可以使用Java 5注解完全规制它们。
下面的代码Message.hbm.xml是将Message POJO映射进数据库的文件。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="sample.entity.Message" table="MESSAGE"> <id type="int" column="id"> <generator class="native"></generator> </id> <property name="message" column="message" type="string"></property> </class> </hibernate-mapping>
看起来复杂性似乎只是从应用程序代码转移到了XML映射文件中。但实际中,由于下述几个原因,情况并非如此。
首先,相比从结果集填充POJO的复杂过程,编辑这个XML文件要容易得多——而且,如果映射进数据库的对象在部署的后期发生了变化,那么修改起来也要容易很多。
其次,我们还避免了JDBC方式所需的复杂的错误处理。但是,这个原因可能是最不重要的,因为即使不借助于Hibernate,也有许多技术可以使错误处理尽可能简化。
最后,Hibernate可以解决对象的关联问题,开发人员可以从数据库中提取一个对象,这个对象与数据库中大量对象的引用相关联。Hibernate将其他提取操作延迟到实际方问这些对象的时候,这可以避免大量的内存开销并提高性能。