持久層是一個應用系統最基本的部份。很顯然的,如果沒有持久層,所有的工作都將丟失 。但是,對不同的人來說持久層意味著不同的東西。持久化時間的長短是選擇持久層儲存媒 介的基本衡量標准之一。例如,對於生命周期為一個用戶會話的數據來說,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裡。