摘要:針對軟件開發(fā)中的持久對象與關(guān)系數(shù)據(jù)庫的存儲矛盾,O/R Mapping提供了溝通對象與關(guān)系數(shù)據(jù)庫的橋梁。論文主要在分析對象/關(guān)系映射機(jī)制的基礎(chǔ)上,引入了目前比較流行對象/關(guān)系映射框架:Hibernate,并分析與研究了這個(gè)的框架結(jié)構(gòu)和運(yùn)行機(jī)制,最后通過一個(gè)實(shí)例說明如何利用Hibernate進(jìn)行對象的持久化操作。
關(guān)鍵字:持久對象;關(guān)系數(shù)據(jù)庫;對象/關(guān)系映射;Hibernate
中圖分類號:TP393文獻(xiàn)標(biāo)識碼:A文章編號:1009-3044(2009)33-9294-03
Research and Implementation of Object/Relational Mapping under Java Environment
HU Min, WANG Huan
(Fault of Computer Science and Information, Hefei University of Technology, Hefei 230009, China)
Abstract: Aimed at the storing contradiction that existed between the persistence object and the relational database, Object/Relational Mapping provides a bridge between them. Based on the analysis of object/relational mapping's mechanism, this thesis describes a new and popular object/relation mapping frame: Hibernate, analyses and researches its framework and runnable mechanism. Finally, through an example, this thesis showed how to persist the object using Hibernate.
Key words: persistence object; relational database; O/R mapping; hibernate
隨著軟件開發(fā)技術(shù)的發(fā)展,面向?qū)ο蠓治觥⒃O(shè)計(jì)、開發(fā)正逐步成為主流軟件工程技術(shù),然而在數(shù)據(jù)庫領(lǐng)域,面向?qū)ο髷?shù)據(jù)庫產(chǎn)品卻未真正成熟,關(guān)系數(shù)據(jù)庫產(chǎn)品依然是開發(fā)的必然選擇。但是對象模型和關(guān)系模型有著完全不同的概念和理論,對象模型基于軟件工程的一些原理,例如抽象、封裝、繼承、聚合和多態(tài),而關(guān)系數(shù)據(jù)模型則基于數(shù)學(xué)原理,特別是集合論的原理。兩種不同的理論基礎(chǔ)導(dǎo)致各自有不同的優(yōu)缺點(diǎn)。如何將面向?qū)ο?OO)技術(shù)的優(yōu)越性與成熟的關(guān)系數(shù)據(jù)庫技術(shù)有機(jī)地結(jié)合起來,這就催生了對象/關(guān)系映射(O/R Mapping)技術(shù)的產(chǎn)生。
1 O/R Mapping框架概述
使用面向?qū)ο蟮恼Z言訪問關(guān)系數(shù)據(jù)庫最簡單,也是最糟糕的辦法,就是在業(yè)務(wù)邏輯層中利用大量的SQL硬編碼語句來實(shí)現(xiàn)對數(shù)據(jù)庫中數(shù)據(jù)的存取。這種模式的優(yōu)點(diǎn)在于開發(fā)的迅速敏捷。但是基于這種模式開發(fā)的系統(tǒng),其維護(hù)性和可擴(kuò)展性差。
一種改進(jìn)的方法是:在業(yè)務(wù)類與底層數(shù)據(jù)庫之間增加數(shù)據(jù)訪問類,封裝與數(shù)據(jù)庫相關(guān)的各種操作,這樣業(yè)務(wù)類便脫離了SQL語句,系統(tǒng)的整體結(jié)構(gòu)也更為清晰。這也是當(dāng)前軟件開發(fā)過程中的主流方法,但是這種方法仍然不能使面向?qū)ο蟮拈_發(fā)者完全擺脫數(shù)據(jù)庫的束縛。
針對上面兩種方法,應(yīng)用程序開發(fā)人員都不能以面向?qū)ο蟮姆椒▉韺ο髷?shù)據(jù)進(jìn)行操作,為此提出了在業(yè)務(wù)邏輯層和關(guān)系數(shù)據(jù)庫之間增加一個(gè)數(shù)據(jù)持久層,負(fù)責(zé)實(shí)現(xiàn)對象和關(guān)系數(shù)據(jù)庫之間的映射,如圖1所示。業(yè)務(wù)邏輯層直接獲取或存貯的就是清晰的對象,中間的轉(zhuǎn)換過程就交給O/R Mapping框架處理了。
2 O/R Mapping機(jī)制
O/R Mapping是將對象的狀態(tài)映射到數(shù)據(jù)庫上,以便提供透明的持久化操作。根據(jù)對象與關(guān)系數(shù)據(jù)庫的特性,O/R Mapping主要通過以下幾個(gè)方面實(shí)現(xiàn):
2.1 對象標(biāo)識符到主鍵的映射
將類映射成關(guān)系數(shù)據(jù)庫的表時(shí),通常將對象標(biāo)識符(一般是對象的某個(gè)屬性)映射成數(shù)據(jù)庫表的主鍵即可。
2.2 類屬性到數(shù)據(jù)表列的映射
在一般情況下,對象的屬性映射到關(guān)系數(shù)據(jù)庫單個(gè)字段上;而對于本身就是對象的屬性,一般要映射到多個(gè)字段上。
2.3 類到數(shù)據(jù)表的映射
類到數(shù)據(jù)表的映射主要討論如何用數(shù)據(jù)表來表達(dá)類之間的繼承關(guān)系。可以采用的映射策略主要有以下3種:
1) 整個(gè)類層次結(jié)構(gòu)使用一個(gè)數(shù)據(jù)實(shí)體:將整個(gè)類層次映射到一張數(shù)據(jù)表中意味著從基類到其所有子孫類的所有屬性都存儲到一張數(shù)據(jù)表中。
2) 每個(gè)具體類使用一個(gè)數(shù)據(jù)實(shí)體:使用這種方法,各個(gè)子類所特有屬性,聯(lián)合從父類中繼承的公共屬性,構(gòu)成表的結(jié)構(gòu)。父類不映射為數(shù)據(jù)庫中的實(shí)體表,只作為子類公共屬性的載體。
3) 每個(gè)類使用一個(gè)數(shù)據(jù)實(shí)體:使用這種方法,為每個(gè)類創(chuàng)建一張表。增加一個(gè)子類時(shí),只需要增加一個(gè)表存儲只屬于這個(gè)子類的屬性。與前兩者比較,對象與數(shù)據(jù)庫的耦合程度是最低的。它也能夠很好地支持多態(tài)性。這種方法的缺點(diǎn)在于生成子類的實(shí)例時(shí),繼承層次多的子類的屬性值還原困難。
2.4 關(guān)系映射
類間關(guān)系映射為鍵值,這是映射的關(guān)鍵,主要是體現(xiàn)類關(guān)系中的關(guān)聯(lián)和聚合,在業(yè)務(wù)邏輯中以編碼的方式實(shí)現(xiàn)其他的關(guān)系。
以上所說的O/R Mapping映射機(jī)制在實(shí)際應(yīng)用中要根據(jù)特定的系統(tǒng)需求,做出適當(dāng)?shù)娜∩帷?/p>
圍繞對象/關(guān)系的映射和持久數(shù)據(jù)的訪問,在Java領(lǐng)域中發(fā)展起來了一些ORM框架,有Hibernate,JDO和Ibatis等,下文將著重分析Hibernate框架。
3 Hibernate
3.1 Hibernate介紹
Hibernate是一個(gè)開源的對象關(guān)系映射框架,它對JDBC進(jìn)行了輕量級的對象封裝,使得Java程序員可以隨心所欲地使用對象編程思想來操縱數(shù)據(jù)庫。整個(gè)系統(tǒng)主要有三層:應(yīng)用層(Application)、基于Hibernate的數(shù)據(jù)持久層(Persistent layer)、數(shù)據(jù)庫層(Database)。在應(yīng)用層主要是對對象進(jìn)行操作;在數(shù)據(jù)庫層主要針對的是關(guān)系型數(shù)據(jù)表。中間的Hibernate層的O/R Mapping在對象范例和關(guān)系范例中建立映射關(guān)系,將應(yīng)用層中對對象的操作直接作用于關(guān)系數(shù)據(jù)庫中的表,使程序員不用再去關(guān)心數(shù)據(jù)庫的操作問題。
3.2 Hibernate運(yùn)行機(jī)制
理解Hibernate的運(yùn)行機(jī)制對應(yīng)用程序的編寫很是重要,如圖2就是Hibernate運(yùn)行機(jī)制。
從圖2中可以明顯地看出Hibernate應(yīng)用首先通過Configuration()方法調(diào)用Mapping Documents進(jìn)行編譯,然后從編譯了的映射文檔集合中創(chuàng)建一個(gè)SessionFactory,這個(gè)SessionFactory為管理類的持久化提供了一種機(jī)制,即Session接口。Session類在持久化數(shù)據(jù)存儲和應(yīng)用程序之間提供了一個(gè)接口,Session接口封裝了一個(gè)JDBC連接,它可以是用戶管理或者是由Hibernate來管理,并且趨向于由單一程序線程使用,然后關(guān)閉和丟棄。
4 Hibernate框架的應(yīng)用
下面以我們常見的高校學(xué)生選課管理信息系統(tǒng)(SCMIS)來說明如何利用Hibernate進(jìn)行數(shù)據(jù)持久化。
以該系統(tǒng)中選課管理為例,在該例包含二個(gè)實(shí)體對象學(xué)生(Student)、課程(Course)其中學(xué)生實(shí)體和課程實(shí)體是多對多的關(guān)系,通過Student__Course關(guān)聯(lián)表進(jìn)行關(guān)聯(lián)。
4.1 配置文件的設(shè)置
在選課管理信息系統(tǒng)中相關(guān)的配置文件有hibernate.cfg.xml和每個(gè)持久化類對應(yīng)的XML文件。在hibernate.cfg.xml配置文件中,包括配置hibernate連接MS SQL Serser數(shù)據(jù)庫的驅(qū)動信息和映射(mapping)到持久化類的配置信息。在持久化類對應(yīng)的配置文件中包含了持久化類的聲明,以及類中各個(gè)屬性到數(shù)據(jù)庫表各個(gè)字段的映射關(guān)系。其屬性可以作為一般值存在也可以是指向其他實(shí)體的關(guān)聯(lián),其在關(guān)系型數(shù)據(jù)庫中體現(xiàn)為數(shù)據(jù)表的外鍵。
限于篇幅原,在此僅寫出學(xué)生信息表對應(yīng)的配置文件Student.hbm.xml內(nèi)容如下:
…………….
4.2 定義持久化類
首先必須編寫2個(gè)實(shí)體類,分別為每個(gè)類的數(shù)據(jù)成員編寫getXXX(),setXXX()方法,其中XXX表示類的數(shù)據(jù)成員。其中Student類與Course類是多對多的關(guān)系,即每個(gè)學(xué)生可以選擇多門課程,而每門課程可以被多個(gè)學(xué)生選中。因此需要在Student類中添加一個(gè)Set類作為容器,來存放與本身相對應(yīng)的Course對象。
public class Student
{/**屬性,和students表中的字段對應(yīng)**/
private Integer id;
…………..
/**和其它類之間的映射關(guān)系**/
Private Set courses;
Public void setId (Integer id)
{this.id = id;}
Public Integer getId () {return id ;}
………………
/**操作和其它對象之間的關(guān)系**/
Public void setCourses(Set co)
{this.courses=co;}
Public Set getCourses ()
{return this.courses ;}
}
4.3 聲名管理Session的類(HibernateUtil.java)
該類用于管理session的生成和關(guān)閉。在Hibernate中,該session幫助實(shí)現(xiàn)和數(shù)據(jù)庫之間的交互。
Public class HibernateUtil {
Private static final SessionFactory sessionFactory;
Static {
try
{SessionFactory = new Configuration ( ) . Configure ( ) . buildSessionFactory ();}
catch (Throwable ex) {. . . }}
Public static final ThreadLocal session = new ThreadLocal () ;
Public static Session currentSession() {
Session s = (Session) session. get ();
if (s = = 1) {
s = sessionFactory. OpenSession ();
session. set (s) ;}
return s ;}
Public static void closeSession () {
Session s = (Session) session. get () ;
if (s! = 1)
s. close () ;
session. set (1) ;
}}
4.4 業(yè)務(wù)層代碼
在業(yè)務(wù)層中,我們就可以使用持久層中的HibernateUtil輔助類生成Session,來完成對對象的持久化,即對對象的保存、更新、刪除、加載、查詢等操作。 如下面就是新建個(gè)學(xué)生對象,持久化到數(shù)據(jù)庫中。
Session session=HibernateUtil.currentSession();
Student student=new Student();
Student.setName (“Li Ming”);
……………………
Transaction tx=session.beginTransaction();
session.save (student);
tx.commit;
session. close;
至此持久層就完成了學(xué)生對象的持久化操作,從用戶角度來看,只有對象存在,所操作的也只有對象,即應(yīng)用程序開發(fā)人員能夠以統(tǒng)一的、面向?qū)ο蟮姆椒ㄟM(jìn)行對象數(shù)據(jù)存取,而不必關(guān)心底層關(guān)系數(shù)據(jù)庫中數(shù)據(jù)存取的實(shí)現(xiàn),從而提高了開發(fā)效率。
5 總結(jié)
O/R Mapping的出現(xiàn)有效地填補(bǔ)了關(guān)系數(shù)據(jù)庫理論與面向?qū)ο罄碚撝g的鴻溝,為基于數(shù)據(jù)的種種應(yīng)用的開發(fā)提供了一種穩(wěn)定、高效、擴(kuò)展性極佳的解決方案。作為一個(gè)優(yōu)秀的持久層框架實(shí)現(xiàn),Hibernate可以有效地進(jìn)行數(shù)據(jù)庫數(shù)據(jù)到業(yè)務(wù)對象的O/R映射,使得程序員專心地實(shí)現(xiàn)業(yè)務(wù)邏輯,而不用分心于繁瑣的數(shù)據(jù)庫方面的邏輯,從而提高開發(fā)成本和效率。
參考文獻(xiàn):
[1] Hibernate.Object/relational mapping and object persistence For java[EB/OL].http://hibernate.bluemars.net/.
[2] Ambler S W.Mapping Objects to Relational Databases:O/R Mapping In Detail[EB/OL].http://www.agiledata.org/essays/mappingObjects.html.
[3] 田珂,謝世波,方馬.J2EE 數(shù)據(jù)持久層的解決方案[J].計(jì)算機(jī)工程,2003,29(22):93-95.
[4] 何錚,陳志剛.對象/關(guān)系映射框架的研究與應(yīng)用[J].計(jì)算機(jī)工程與應(yīng)用,2003,26(6):188-191.
[5] 徐茹枝,丁昊志,單波.對象關(guān)系映射框架的研究與設(shè)計(jì)[J].華北電力大學(xué)學(xué)報(bào),2006,33(4):69-72.
[6] 夏聽,曹曉鋼,唐勇.深入淺出HIBERNATE[M].北京:電子工業(yè)出版社,2005.
[7] 孫衛(wèi)琴.精通HIBERNATE:Java對象持久化技術(shù)詳解[M].北京:電子工業(yè)出版社,2005.