Hibernate In Action
中文版
Java 爱好者 http://www.JavaFan.NET 制作
第二章 引入与集成Hibernate
理解一些Java应用对对象-关系映射的需求是对的,但你可能更急于看到活动的
Hibernate。让我们从一个简单的例子开始,展示它的一些能力。
你可能知道,编程书籍通过一个“Hello World”例子开始是一项传统。在本章中,我们
将遵循这个传统,使用一个相对简单的“Hello World”程序来介绍Hibernate。然而,简单
地在控制台窗口上打印一条消息并不足以实际地展示Hibernate。相反,我们的程序会将新建
的对象存储到数据库中,更新它们,并且执行查询从数据库中取出它们。
本章是以后各章的基础。除了这个规范的“Hello World”例子,我们还介绍了核心的
Hibernate API,并说明了如何在各种不同的运行环境例如J2EE应用服务器和独立的应用中配
置Hibernate。
2.1 Hibernate中的“Hello World”
Hibernate应用定义了映射到数据库表的持续类。我们的“Hello World”例子由一个类
和一个映射文件组成。让我们看一下一个简单的持续类是什么样子的,映射是如何指定的,
和我们使用Hibernate持续类的实例可以做的一些其它的事情。
这个简单应用的目标是在数据库中存储消息并且取出它们进行显示。这个应用有一个简
单的持续类“Message”,表示了这些用于打印的消息。我们的Message类如清单2.1所示。
package hello;
public class Message {
// 标识符属性
private Long id;
Hibernate In Action
中文版
Java 爱好者 http://www.JavaFan.NET 制作
// 消息文本
private String text;
// 另一个消息的引用
private Message nextMessage;
private Message() {}
public Message(String text) {
this.text = text;
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Message getNextMessage() {
return nextMessage;
}
public void setNextMessage(Message nextMessage) {
this.nextMessage = nextMessage;
}
}
(清单2.1)
我们的Message类有三个属性:标识符属性,消息文本和另一个消息的引用。标识符属性
允许应用访问数据库识别——持续性对象的主键。如果两个Message实例具有相同的标识符
值,则它们表示了数据库中相同的行。我们将标识符属性的类型定义成了Long,但这并不是
必须的。实际上,像你将要看到的一样,Hibernate允许任意的标识符类型。
Hibernate In Action
中文版
Java 爱好者 http://www.JavaFan.NET 制作
你可能已经注意到了Message类的所有属性都具有JavaBean风格的属性访问方法。这个类
也包含一个没有参数的构造方法。在我们的例子中使用的持续类几乎总是与此有些相似。
Message类的实例可以由Hibernate进行管理(对其持续化),但这也不是必须的。因为
Message对象没有实现任何Hibernate特定的类或接口,我们可以像任何其它Java类那样使用
它:
Message message = new Message("Hello World");
System.out.println( message.getText() );
这段代码精确地完成了我们刚提到过的对“Hello World”应用的期望:将“Hello World”
打印到控制台上。这有点像我们在自作聪明;实际上,我们展示了Hibernate区别于其它一些
持续性解决方案例如EJB实体Bean的一项重要特征。从根本上讲我们的持续类可以在任意的执
行环境中使用——不需要专门的容器。当然,你到这里来是想看一下Hibernate,因此让我们
将一个新的Message保存到数据库里:
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Message message = new Message("Hello World");
session.save(message);
tx.commit();
session.close();
这段代码调用了Hibernate的Session和 Transaction接 口 (很快我们就会开始介绍
getSessionFactory()方法)。它与下面这条SQL语句的执行结果相似:
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
values (1, 'Hello World', null)
继续——Message_ID字段的初始值非常奇怪。我们没有在任何地方设置Message类的id属
Hibernate In Action
中文版
Java 爱好者 http://www.JavaFan.NET 制作
性,因此我们可能认为它是null,对吗?实际上,id属性是比较特别的:它是一个标识符属
性——它持有一个生成的唯一值(稍候,我们将讨论这个值是如何生成的)。当调用save方法
时,这个值通过Hibernate赋给了Message类的实例。
对这个例子来说,我们假定MESSAGES表早已存在了。在第9章,我们将说明只使用映射文
件里的信息,如何让Hibernate自动创建你的应用所需的表(不用你手工编写更多的SQL)。当
然,我们希望我们的“Hello World”程序能将消息打印到控制台上。现在我们的数据库里已
经有了一条消息,我们准备进行展示了。下一个例子按字母顺序从数据库中取出所有的消息,
并打印它们:
Session newSession = getSessionFactory().openSession();
Transaction newTransaction = newSession.beginTransaction();
List messages =
newSession.find("from Message as m order by m.text asc");
System.out.println( messages.size() + " message(s) found:" );
for ( Iterator iter = messages.iterator(); iter.hasNext(); ) {
Message message = (Message) iter.next();
System.out.println( message.getText() );
}
newTransaction.commit();
newSession.close();
文本串“from Message as m order by m.text asc”是一个使用Hibernate自己的查询
语言(HQL)表示的查询。当调用find()方法时,这个查询在内部被转化成下面的SQL语句:
select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
from MESSAGES m
order by m.MESSAGE_TEXT asc
下面的消息会被打印出来: