持久层是一个应用系统最基本的部份。很显然的,如果没有持久层,所有的工作都将丢失。但是,对不同的人来说持久层意味着不同的东西。持久化时间的长短是选择持久层储存媒介的基本衡量标准之一。例如,对于生命周期为一个用户会话的数据来说,Http session是非常合适的。与之对应的,跨越多个session,或者多个用户的持久化则需要一个数据库来保持。数据的数量是另一个非常重要的衡量标准。例如,最佳实践表明大量的数据最好不要被 存储在一个Http会话中。在这些情况下,你都应该考虑使用数据库。在这篇文章中,我们的目标就是数据库持久层。
你选择的数据库类型对你有架构与设计都有重要的影响。作为面向对象的开发人员,我们倾向于把数据描绘成描述手上商业问题的一组相互关联的对象—这常被称为域模型。 但是,最常用的存储媒介是基于关系模型的。除非我们的对象模型映射成一个关系结构,否则 内存中我们数据的表示就会与持久化它的方法不一致。这个问题也被称作不对称问题。最流行的解决这种不对称问题的是一组被称为对象关系映射工具。一个ORM工具是被用来把数据从对象视图转换为关系型、提供诸如创建、读、更新、删除(CRUD)等持久性服务的 软件。有许多的关于ORM工具的论文,但是从本质上来说,他们谈论的都是对象映射模式。最流行的ORM工具是开源的Hibernate工程。
在这篇文章中,我们展示了如何在一个Struts项目中应用Hibernate。另外,我们将展示如何建立一个Struts插件来提升你系统的性能。
处方
在这个文摘中,我们使用一个例子来展示你在struts项目中使用hibernate时所需要的所有东西。我们将建立一个应用程序来获取和展示从化学元素周期表里取出的元素。这个应用程
序提供给用户一个查找页来通过元素符号来查找元素。应用程序将查询数据库里匹配这个元素符号名的记录并返回查找到的元素信息来响应用户请求。
首先我们将展示如何启动Hypersonic 服务器。当数据库 服务器启动后,我们建立示例程序所需要的表与数据。一旦数据库准备运行了,我们将建立使用Hypersonic数据库服务器所需的Hibernate的所有东西。接下来的步骤是在action里调用Hibernate来处理数据库读取来响应查询请求。因为建立Hibernate的Factory对象是非常耗资源的,我们建立一个Struts plug-in来建立factory并把它保存在context里。
让我们从建立Hypersonic数据库服务器开始。你需要从http://hsqldb.Sourceforge.net/下载它。放置hsqldb.jar在你的classpath路径里,从Dos窗口中敲入以下命令来启动Hypersonic:
java org.hsqldb.Server
虽然不同版本的Hypersonic的服务器响应不同。下面的应答是典型的Hypersonic已经准备好响应数据库请求的应答:
Server 1.6 is running
Press [Ctrl]+{c} to abort
随着数据库服务器的启动,我们可以建表和填充数据,如下列表1所示:
Listing 1. 建立元素表
create table elements (id integer(3) IDENTITY,
name char(30),
number char(30),
mass char(30),
symbol char(2));
CREATE UNIQUE INDEX ui_elements_pk ON elements (symbol)insert into elements ( name, number, mass, symbol) values ('Manganese','25','55','Mn');insert into elements ( name, number, mass, symbol) values ('Zinc','30','65','Zn');insert into elements ( name, number, mass, symbol) values ('Thulium','69','169','Tm');insert into elements ( name, number, mass, symbol) values ('Californium','98','251','Cf');insert into elements ( name, number, mass, symbol) values ('Gold','79','197','Au');insert into elements ( name, number, mass, symbol) values ('Ytterbium','70','173','Yb');insert into elements ( name, number, mass, symbol) values ('Molybdenum','42','96','Mo');insert into elements ( name, number, mass, symbol) values ('Palladium','46','106','Pd');
列表1是建立表的SQL语句,在symbol列上建立唯一索引,插入上面那些化学周期元素。当然你也可以从你高校的化学书本里面找出更多的一些数据插入。
列表2是用来存储从数据库取出数据的JavaBean对象:
Listing 2. JavaBean元素
package com.strutsrecipes.hibernate.beans;public class Element {
private String name;
private String symbol;
private String number;
private String mass;
private int id;
public Element() { super();
} public Element(String name, String symbol, String number, String mass) {
this.name = name;
this.symbol = symbol;
this.number = number;
this.mass = mass;
} public int getId() { return id;
} public void setId(int id) { this.id = id;
} public String getMass() { return mass;
} public String getName() { return name;
} public String getNumber() { return number;
} public String getSymbol() { return symbol;
} public void setMass(String mass) { this.mass = mass;
} public void setName(String name) { this.name = name;
} public void setNumber(String number) { this.number = number;
} public void setSymbol(String symbol) { this.symbol = symbol;
}}
Hibernate是一个对象-关系映射工具。它的任务是映射对象到关系型表,反之亦然。所以,我们必须告诉Hibernate如何映射列到JavaBean的属性上。这个是通过Element.hbm.xml文件来完成的。这份文件里面包含的信息用来授予Hibernate从表里面拷贝数据到Elements JavaBean的权利。如果我们使用Hibernate来更新数据,Element.hbm.xml文件里的信息将被用来解析从Elements JavaBean来的数据来生成更新的SQL语句。列表3显示了Element.hbm.xml。
Listing 3. Element.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sf.net/hibernate-mapping-2.0.dtd"><hibernate-mapping>
<class name="com.strutsrecipes.hibernate.beans.Element" table="elements">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<property name="number" column="number"/>
<property name="mass" column="mass"/>
<property name="symbol" column="symbol"/>
</class></hibernate-mapping>
让我们跳到列表3
我们声明了与elements表相联系的类文件的完整的包名。然后我们声明了表的名字与这个类相关联。接下来我们声明从JavaBean的id属性到表的id列的映射。因为property和column属性都有相同的值,我们本来可以忽略column属性,但是为了清晰起见,我们还是把column列出来。 <id>是个特殊的标签。它被用来声明表的主键。闭合的标签<generator>表示Hibernate以最适合数据库实现的方式生成该主键。你可以参考Hibernate文档有关标签<id>的更多信息。最后我们为其它的JavaBean属性做声明。为了清晰起见,column属性再次被声明。
一旦映射文件被详细的分析,那一切都非常的明晰了。它简单地声明了表与类的映射和JavaBean属性与表的列名的映射。接下来我将告诉你在哪里放置这个文件。
接下来,我们通过声明环境信息来配置Hibernate。在列表4我们展示Hibernate.cfg.xml文件。
Listing 4. hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"><hibernate-configuration>
<session-factory>
<property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property>
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.username">sa</property> <property name="connection.password"></property> <property name="connection.url">jdbc:hsqldb:hsql://127.0.0.1</property>
<property name="show_sql"> </property> <property name="">true</property>
<mapping resource="/com/strutscookbook/hibernate/beans/Element.hbm.xml"/></session-factory></hibernate-configuration>
让我们跳到列表4
我们以指定数据库实现方言开始,允许Hibernate充分利用实现特殊化的属性。我们声明Hypersonic方言。我们可以参考Hibernate文档以选择数据库相应的方言。然后我们声明数据库 驱动。必须保证这个驱动在应用程序的classpath上。然后我们声明数据库的用户名,数据库密码,连接数据库的URL。接下来我们通知Hibernate在日志里显示运行时生成的SQL语句。
Hibernate.cfg.xml文件必须被放在你的classpath里。