Hibernate定义了一些映射到数据库表的持久化类。我们的HelloWorld包含了一个类和一个映射文件。让我们来看看持久化类的样子,映射是如何指定的,以及利用Hibernate的持久化类我们到底能做些什么事情。
我们的例子的功能是将一些信息存到数据库中,然后再从数据库中将它们检索出来在页面上显示。这个程序包含了类Message,在清单2.1中你将看到这个类的具体内容。
清单2.1 Message.java一个简单的持久化类
package hello;
public class Message {
private Long id;
private String text;
private Message nextMessage;
private Message() {
}
public Message(String text) {
this.text = text;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the text
*/
public String getText() {
return text;
}
/**
* @param text the text to set
*/
public void setText(String text) {
this.text = text;
}
/**
* @return the nextMessage
*/
public Message getNextMessage() {
return nextMessage;
}
/**
* @param nextMessage the nextMessage to set
*/
public void setNextMessage(Message nextMessage) {
this.nextMessage = nextMessage;
}
}
Message类有三个属性,ID、消息文本以及指向下一条Message的引用,在这里ID将被用作和数据表的主键相关联。也就是说,如果两个Message拥有相同的ID,那么它们将对应数据表的同一行。在这里,Message使用Long作为ID的类型,需要注意的是这并不是必须的。实际上,Hibernate可以使用任何类型作为标识。
你会注意到Message其实是一个JavaBean,同时它拥有一个默认的构造函数。
Message类的对象将会被Hibernate自动的持久化,由于Message并没有实现Hibernate特定的类或者接口,所以我们可以像使用其他Java类一样来使用它:
Message message=new Message(“Hello World;”);
System.out.println(message.getText());
这个代码片段就是这个程序要实现的事情,将Hello World打印出来。这看起来有点故弄玄虚,实际上我们正在示范Hibernate和其他的持久化解决方案如EJB到底有什么不同之处。我们的持久化类可以在任意的环境中执行,它并不需要特定的容器。当然,你是来学习Hibernate的,那么现在就看看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接口。它的执行结果和下面的SQL语句很相似:
insert into MESSAGES(MESSAGE_ID,MESSAGE_NEXT,NEXT_MESSAGE_ID) values(1,’Hello World’,null);
等一下,我么看到MESSAGE_ID字段有点奇怪,我们并没有在代码中为ID设置任何值,所以它应该是NULL才对。实际上,ID属性比较特殊,它代表了对象的主键,这个值由Hibernate自动生成。当save方法被调用的时候,这个值由Hibernate分配给Message对象。
在这个例子中,我们假设MESSAGES表已经存在。在第九章中,我们将会展示如何自动创建一个表。当然,我们希望“Hello World”被打印到控制台。下一个例子就是将所有的MESSAGE从数据库表中读出来并打印。
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.next()){
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。这句HQL将会被翻译成为SQL:select m.MESSAGE_ID,m.MESSAEG_TEXT,m.MESSAGE_NEXT_ID from
MESSAGES m order by m.MESSAGE_TEXT asc
代码的执行结果如下:
1 message(s) found:
Hello World.
如果你以前没有使用过类似Hibernate的ORM框架的话,那么你可能会寻找SQL在哪里,实际上它们是在运行的时候被自动生成。
为了使上面的代码真正的实现,Hibernate需要更多的信息来知道如何持久化Message对象。这些必要的信息通常通过XML映射文件来呈现,这个映射文件定义了Message的属性如何映射到表的数据列当中。让我们来看一下清单2.2的映射文件。
清单2.2 一个简单的HIbernate映射文件
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
映射文件告诉Hibernate如何将Message类映射到MESSAGES表,identifier属性映射到MESSAGE_ID,text属性映射到MESSAGE_TEXT,nextMessage属性映射到NEXT_MESSAGE_ID,同时具有many-to-one属性。
正如你所看到的,XML映射文件很容易理解。你可以很轻易的手工书写和维护它。在第3章,我们将讨论如何在代码中用注释来生成xml文件。无论你选用哪种方法,Hibernate都拥有充足的信息来来自动生成SQL。你不再需要把精神花在手写SQL上。
现在,让我们把原始Message的信息修改掉,然后为第一条消息创建一条关联的消息。
清单2.3 更新一条消息
Session session=getSessionFactory(),openSession();
Transaction tx=session.beginTransaction();
Message message=(Message)sessin.load(Message.class,new Long(1));
message.setText(“Greetings Earthing”);
Message nextMessage=new Messsage(“Take me to your leader(please));
message.setNextMessage(nextMessage);
tx.commit();
session.close();
这段代码调用三段SQL:
select m.MESSAGE_ID,m.MESSAGE_TEXT,m.NEXT_MESSAGE_ID from MESSAGES m where m.MESSAGE_ID=1
insert into MESSAGES(MESSAGE_ID,MESSAGE_TEXT,NEXT_MESSAGE_ID) values(2,’Take me to your leader (please)’,null(
update MESSAGES set MESSAGE_TEXT =’Greetings Earthing’,NEXT_MESSAGE_ID=2 where MESSAGE_ID=’1’
这里需要注意的是Hibernate如何知道text和nextMessage改变了。这里需要利用的是自动脏数据检查。当对象的属性在事务中发生了变化的时候,这个特性能够通知Hibernate来更新数据库。类似的,当为第一条Message创建一个新的Message的时候,也会自动被持久化。这种特性被称为串联(cascading)保存:通过调用save()方法来完成对象的保存,只要这个持久化对象能够被访问的话。你会注意到SQL语句的顺序并不一定和我们设置属性的顺序一致。Hibernate使用了经典算法来保持足够的效率。这会被成为Transactinal write-behind。
如果我们重新运行“Hello World”,它会打印
2 message(s) found:
Greetings Earthing
到现在为止,我们一直在运行Hello World程序。现在就让我们回过头来看看Hibernate主要的API。