Hibernate 的原理與設(shè)置
發(fā)表時(shí)間:2024-05-28 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]也許你聽說過Hibernate的大名,但可能一直不了解它,也許你一直渴望使用它進(jìn)行開發(fā),那么本文正是你所需要的!在本文中,我向大家重點(diǎn)介紹Hibernate的核心API調(diào)用庫,并講解一下它的基本配置。 看完本文后,我相信你對(duì)什么是ORM(對(duì)像/關(guān)系映射)以及它的優(yōu)點(diǎn)會(huì)有一個(gè)深刻的認(rèn)識(shí),我們先通...
也許你聽說過Hibernate的大名,但可能一直不了解它,也許你一直渴望使用它進(jìn)行開發(fā),那么本文正是你所需要的!在本文中,我向大家重點(diǎn)介紹Hibernate的核心API調(diào)用庫,并講解一下它的基本配置。
看完本文后,我相信你對(duì)什么是ORM(對(duì)像/關(guān)系映射)以及它的優(yōu)點(diǎn)會(huì)有一個(gè)深刻的認(rèn)識(shí),我們先通過一個(gè)簡單的例子開始來展現(xiàn)它的威力。
正如一些傳統(tǒng)的經(jīng)典計(jì)算機(jī)文章大都會(huì)通過一個(gè)“hello,world”的例子開始講解一樣,我們也不例外,我們也將從一個(gè)相對(duì)簡單的例子來闡述Hibernate的開發(fā)方法,但如果要真正闡述Hibernate的一些重要思想,僅僅靠在屏幕上打印一些字符是遠(yuǎn)遠(yuǎn)不夠的,在我們的示例程序中,我們將創(chuàng)建一些對(duì)象,并將其保存在數(shù)據(jù)庫中,然后對(duì)它們進(jìn)行更新和查詢。
閱讀導(dǎo)航
“Hello World”“Hello world”示例程序讓您對(duì)Hibernate有一個(gè)簡單的認(rèn)識(shí)。
理解Hibernate的架構(gòu)介紹Hibernate接口的主要功能。
核心接口Hibernate有5個(gè)核心接口,通過這幾個(gè)接口開發(fā)人員可以存儲(chǔ)和獲得持久對(duì)象,并且能夠進(jìn)行事務(wù)控制
一個(gè)重要的術(shù)語:TypeType是Hibernate發(fā)明者發(fā)明的一個(gè)術(shù)語,它在整個(gè)構(gòu)架中是一個(gè)非常基礎(chǔ)、有著強(qiáng)大功能的元素,一個(gè)Type對(duì)象能將一個(gè)Java類型映射到數(shù)據(jù)庫中一個(gè)表的字段中去。
策略接口Hibernate與某些其它開源軟件不同的還有一點(diǎn)――高度的可擴(kuò)展性,這通過它的內(nèi)置策略機(jī)制來實(shí)現(xiàn)。
基礎(chǔ)配置Hibernate可以配置成可在任何Java環(huán)境中運(yùn)行,一般說來,它通常被用在2-3層的C/S模式的項(xiàng)目中,并被部署在服務(wù)端。
創(chuàng)建一個(gè)SessionFactory對(duì)象要?jiǎng)?chuàng)建一個(gè)SessionFactory對(duì)象,必須在Hibernate初始化時(shí)創(chuàng)建一個(gè)Configuration類的實(shí)例,并將已寫好的映射文件交由它處理。
“Hello World”
Hibernate應(yīng)用程序定義了一些持久類,并且定義了這些類與數(shù)據(jù)庫表格的映射關(guān)系。在我們這個(gè)“Hello world”示例程序中包含了一個(gè)類和一個(gè)映射文件。讓我們看看這個(gè)簡單的持久類包含有一些什么?映射文件是怎樣定義的?另外,我們該怎樣用Hibernate來操作這個(gè)持久類。
我們這個(gè)簡單示例程序的目的是將一些持久類存儲(chǔ)在數(shù)據(jù)庫中,然后從數(shù)據(jù)庫取出來,并將其信息正文顯示給用戶。其中Message正是一個(gè)簡單的持久類:,它包含我們要顯示的信息,其源代碼如下:
列表1 Message.Java 一個(gè)簡單的持久類
package hello;
public class Message {
private Long id;
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;
}
}
Message類有三個(gè)屬性:Message的id 、消息正文、以及一個(gè)指向下一條消息的指針。其中id屬性讓我們的應(yīng)用程序能夠唯一的識(shí)別這條消息,通常它等同于數(shù)據(jù)庫中的主鍵,如果多個(gè)Message類的實(shí)例對(duì)象擁有相同的id,那它們代表數(shù)據(jù)庫某個(gè)表的同一個(gè)記錄。在這里我們選擇了長整型作為我們的id值,但這不是必需的。Hibernate允許我們使用任意的類型來作為對(duì)象的id值,在后面我們會(huì)對(duì)此作詳細(xì)描述。
你可能注意到Message類的代碼類似于JavaBean的代碼風(fēng)格,并且它有一個(gè)沒有參數(shù)的構(gòu)造函數(shù),在我們以后的代碼中我將繼續(xù)使用這種風(fēng)格來編寫持久類的代碼。
Hibernate會(huì)自動(dòng)管理Message類的實(shí)例,并通過內(nèi)部機(jī)制使其持久化,但實(shí)際上Message對(duì)象并沒有實(shí)現(xiàn)任何關(guān)于Hibernate的類或接口,因此我們也可以將它作為一個(gè)普通的Java類來使用:
Message message = new Message("Hello World");
System.out.println( message.getText() );
以上這段代碼正是我們所期望的結(jié)果:它打印“hello world”到屏幕上。但這并不是我們的最終目標(biāo);實(shí)際上Hibernate與諸如EJB容器這樣的環(huán)境在持久層實(shí)現(xiàn)的方式上有很大的不同。我們的持久類(Message類)可以用在與容器無關(guān)的環(huán)境中,不像EJB必須要有EJB容器才能執(zhí)行。為了能更清楚地表現(xiàn)這點(diǎn),以下代碼將我們的一個(gè)新消息保存到數(shù)據(jù)庫中去:
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Message message = new Message("Hello World");
session.save(message);
tx.commit();
session.close();
以上這段代碼調(diào)用了Hibernate的Session和Transaction接口(關(guān)于getSessionFactory()方法我們將會(huì)馬上提到)。它相當(dāng)于我們執(zhí)行了以下SQL語句:
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
values (1, 'Hello World', null)
在以上的SQL語句中,MESSAGE_ID字段到底被初始化成了什么值呢?由于我們并沒有在先前的代碼中為message對(duì)象的id屬性賦與初始值,那它是否為null呢?實(shí)際上Hibernate對(duì)id屬性作了特殊處理:由于它是一個(gè)對(duì)象的唯一標(biāo)識(shí),因此當(dāng)我們進(jìn)行save()調(diào)用時(shí),Hibernate會(huì)為它自動(dòng)賦予一個(gè)唯一的值(我們將在后面內(nèi)容中講述它是如何生成這個(gè)值的)。
我們假設(shè)你已經(jīng)在數(shù)據(jù)庫中創(chuàng)建了一個(gè)名為MESSAGE的表,那么既然前面這段代碼讓我們將Message對(duì)象存入了數(shù)據(jù)庫中,那么現(xiàn)在我們就要將它們一一取出來。下面這段代碼將按照字母順序,將數(shù)據(jù)庫中的所有Message對(duì)象取出來,并將它們的消息正文打印到屏幕上:
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();
在以上這段代碼中,你可能被find()方法的這個(gè)參數(shù)困擾著:"from Message as m order by m.text asc",其實(shí)它是Hibernate自己定義的查詢語言,全稱叫Hibernate Query Language(HQL)。通俗地講HQL與SQL的關(guān)系差不多就是方言與普通話之間的關(guān)系,咋一看,你會(huì)覺得它有點(diǎn)類似于SQL語句。其實(shí)在find()調(diào)用時(shí),Hibernate會(huì)將這段HQL語言翻譯成如下的SQL語句:
select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
from MESSAGES m
order by m.MESSAGE_TEXT asc
以下就是運(yùn)行結(jié)果:
1 message(s) found:
Hello World
如果你以前沒有ORM(對(duì)象-關(guān)系映射)的開發(fā)經(jīng)驗(yàn),那你可能想在代碼的某個(gè)地方去尋找這段SQL語句,但在Hibernate中你可能會(huì)失望:它根本不存在!所有就SQL語句都是Hibernate動(dòng)態(tài)生成的。
也許你會(huì)覺得還缺點(diǎn)什么,對(duì)!僅憑以上代碼Hibernate是無法將我們的Message類持久化的。我們還需要一些更多的信息,這就是映射定義表!這個(gè)表在Hibernate中是以XML格式來體現(xiàn)的,它定義了Message類的屬性是怎樣與數(shù)據(jù)庫中的MESSAGES表的字段進(jìn)行一一對(duì)應(yīng)的,列表2是這個(gè)示例程序的映射配置文件清單:
列表2:示例程序的對(duì)象-關(guān)系映射表
。?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
。糷ibernate-mapping>
。糲lass name="hello.Message" table="MESSAGES">
。糹d name="id" column="MESSAGE_ID">
。糶enerator class="increment"/>
。/id>
<property name="text" column="MESSAGE_TEXT"/>
。糾any-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/>
</class>
。/hibernate-mapping>
以上這個(gè)文檔告訴Hibernate怎樣將Message類映射到MESSAGES表中,其中Message類的id屬性與表的MESSAGE_ID字段對(duì)應(yīng),text屬性與表的MESSAGE_TEXT字段對(duì)應(yīng),nextMessage屬性是一個(gè)多對(duì)一的關(guān)系,它與表中的NEXT_MESSAGE_ID相對(duì)應(yīng)。
相對(duì)于有些開源項(xiàng)目來說,Hibernate的配置文件其實(shí)是很容易理解的。你可以輕松地修改與維護(hù)它。只要你定義好了持久類與數(shù)據(jù)庫中表字段的對(duì)應(yīng)關(guān)系就行了,Hibernate會(huì)自動(dòng)幫你生成SQL語句來對(duì)Message對(duì)象進(jìn)行插入、更新、刪除、查找工作,你可以不寫一句SQL語句,甚至不需要懂得SQL語言!
現(xiàn)在讓我們做一個(gè)新的試驗(yàn),我們先取出第一個(gè)Message對(duì)象,然后修改它的消息正文,最后我們再生成一個(gè)新的Message對(duì)象,并將它作為第一個(gè)Message對(duì)象的下一條消息,其代碼如下:
列表3 更新一條消息
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
// 1 is the generated id of the first message
Message message =(Message) session.load( Message.class, new Long(1) );
message.setText("Greetings Earthling");
Message nextMessage = new Message("Take me to your leader (please)");
message.setNextMessage( nextMessage );
tx.commit();
session.close();
以上這段代碼在調(diào)用時(shí),Hibernate內(nèi)部自動(dòng)生成如下的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 Earthling', NEXT_MESSAGE_ID = 2
where MESSAGE_ID = 1
當(dāng)?shù)谝粋(gè)Message對(duì)象的text屬性和nextMessage被程序修改時(shí),請注意Hibernate是如何檢測到這種變化,并如何在數(shù)據(jù)庫中自動(dòng)對(duì)它更新的。這實(shí)際上是Hibernate的一個(gè)很有價(jià)值的特色,我們把它稱為“自動(dòng)臟數(shù)據(jù)檢測”,Hibernate的這個(gè)特色使得當(dāng)我們修改一個(gè)持久對(duì)象的屬性后,不必顯式地通知Hibernate去將它在數(shù)據(jù)庫中進(jìn)行更新。同樣的,當(dāng)?shù)谝粋(gè)Message對(duì)象調(diào)用setNextMessage()方法將第二個(gè)Message對(duì)象作為它的下一條消息的引用時(shí),第二條消息會(huì)無需調(diào)用save()方法,便可以自動(dòng)地保存在數(shù)據(jù)庫中。這種特色被稱為“級(jí)聯(lián)保存”,它也免去了我們顯式地對(duì)第二個(gè)Message對(duì)象調(diào)用save()方法之苦。
如果我們再運(yùn)行先前的那段將數(shù)據(jù)庫中所有的Message對(duì)象都打印出來的代碼,那它的運(yùn)行結(jié)果如下:
2 message(s) found:
Greetings Earthling
Take me to your leader (please)
“Hello world”示例程序現(xiàn)在介紹完畢。我們總算對(duì)Hibernate有了一個(gè)簡單的認(rèn)識(shí),下面我們將回過頭來,對(duì)Hibernate的主要API調(diào)用作一下簡要的介紹:
理解Hibernate的架構(gòu)
當(dāng)你想用Hibernate開發(fā)自己的基于持久層的應(yīng)用時(shí),第一件事情應(yīng)當(dāng)是熟悉它的編程接口。Hibernate的API接口設(shè)計(jì)得盡量簡潔明了,以方便開發(fā)人員。然而實(shí)際上由于ORM的復(fù)雜性,它的API一般都不可能設(shè)計(jì)得很簡單。但是別擔(dān)心,你沒有必要一下子了解所有的Hibernate的API接口。
我們將應(yīng)用層放在了持久層的上部,實(shí)際上在傳統(tǒng)的項(xiàng)目中,應(yīng)用層充當(dāng)著持久層的一個(gè)客戶端角色。但對(duì)于一些簡單的項(xiàng)目來說,應(yīng)用層和持久層并沒有區(qū)分得那么清楚,這也沒什么,在這種情況下你可以將應(yīng)用層和持久層合并成了一層。
Hibernate的接口大致可以分為以下幾種類型:
· 一些被用戶的應(yīng)用程序調(diào)用的,用來完成基本的創(chuàng)建、讀取、更新、刪除操作以及查詢操作的接口。這些接口是Hibernate實(shí)現(xiàn)用戶程序的商業(yè)邏輯的主要接口,它們包括Session、Transaction和Query。
· Hibernate用來讀取諸如映射表這類配置文件的接口,典型的代表有Configuration類。
· 回調(diào)(Callback)接口。它允許應(yīng)用程序能對(duì)一些事件的發(fā)生作出相應(yīng)的操作,例如Interceptor、Lifecycle和Validatable都是這一類接口。
· 一些可以用來擴(kuò)展Hibernate的映射機(jī)制的接口,例如UserType、CompositeUserType和IdentifierGenerator。這些接口可由用戶程序來實(shí)現(xiàn)(如果有必要)。
Hibernate使用了J2EE架構(gòu)中的如下技術(shù):JDBC、JTA、JNDI。其中JDBC是一個(gè)支持關(guān)系數(shù)據(jù)庫操作的一個(gè)基礎(chǔ)層;它與JNDI和JTA一起結(jié)合,使得Hibernate可以方便地集成到J2EE應(yīng)用服務(wù)器中去。
在這里,我們不會(huì)詳細(xì)地去討論Hibernate API接口中的所有方法,我們只簡要講一下每個(gè)主要接口的功能,如果你想了解得更多的話,你可以在Hibernate的源碼包中的net.sf.hibernate子包中去查看這些接口的源代碼。下面我們依次講一下所有的主要接口:
核心接口
以下5個(gè)核心接口幾乎在任何實(shí)際開發(fā)中都會(huì)用到。通過這些接口,你不僅可以存儲(chǔ)和獲得持久對(duì)象,并且能夠進(jìn)行事務(wù)控制。
Session接口
Session接口對(duì)于Hibernate 開發(fā)人員來說是一個(gè)最重要的接口。然而在Hibernate中,實(shí)例化的Session是一個(gè)輕量級(jí)的類,創(chuàng)建和銷毀它都不會(huì)占用很多資源。這在實(shí)際項(xiàng)目中確實(shí)很重要,因?yàn)樵诳蛻舫绦蛑,可能?huì)不斷地創(chuàng)建以及銷毀Session對(duì)象,如果Session的開銷太大,會(huì)給系統(tǒng)帶來不良影響。但值得注意的是Session對(duì)象是非線程安全的,因此在你的設(shè)計(jì)中,最好是一個(gè)線程只創(chuàng)建一個(gè)Session對(duì)象。
在Hibernate的設(shè)計(jì)者的頭腦中,他們將session看作介于數(shù)據(jù)連接與事務(wù)管理一種中間接口。我們可以將session想象成一個(gè)持久對(duì)象的緩沖區(qū),Hibernate能檢測到這些持久對(duì)象的改變,并及時(shí)刷新數(shù)據(jù)庫。我們有時(shí)也稱Session是一個(gè)持久層管理器,因?yàn)樗@一些持久層相關(guān)的操作,諸如存儲(chǔ)持久對(duì)象至數(shù)據(jù)庫,以及從數(shù)據(jù)庫從獲得它們。請注意,Hibernate 的session不同于JSP應(yīng)用中的HttpSession。當(dāng)我們使用session這個(gè)術(shù)語時(shí),我們指的是Hibernate中的session,而我們以后會(huì)將HttpSesion對(duì)象稱為用戶session。
SessionFactory 接口
這里用到了一個(gè)設(shè)計(jì)模式――工廠模式,用戶程序從工廠類SessionFactory中取得Session的實(shí)例。
令你感到奇怪的是SessionFactory并不是輕量級(jí)的!實(shí)際上它的設(shè)計(jì)者的意圖是讓它能在整個(gè)應(yīng)用中共享。典型地來說,一個(gè)項(xiàng)目通常只需要一個(gè)SessionFactory就夠了,但是當(dāng)你的項(xiàng)目要操作多個(gè)數(shù)據(jù)庫時(shí),那你必須為每個(gè)數(shù)據(jù)庫指定一個(gè)SessionFactory。
SessionFactory在Hibernate中實(shí)際起到了一個(gè)緩沖區(qū)的作用,它緩沖了Hibernate自動(dòng)生成的SQL語句和一些其它的映射數(shù)據(jù),還緩沖了一些將來有可能重復(fù)利用的數(shù)據(jù)。
Configuration 接口
Configuration接口的作用是對(duì)Hibernate進(jìn)行配置,以及對(duì)它進(jìn)行啟動(dòng)。在Hibernate的啟動(dòng)過程中,Configuration類的實(shí)例首先定位映射文檔的位置,讀取這些配置,然后創(chuàng)建一個(gè)SessionFactory對(duì)象。
雖然Configuration接口在整個(gè)Hibernate項(xiàng)目中只扮演著一個(gè)很小的角色,但它是啟動(dòng)hibernate時(shí)你所遇到的每一個(gè)對(duì)象。
Transaction 接口
Transaction接口是一個(gè)可選的API,你可以選擇不使用這個(gè)接口,取而代之的是Hibernate的設(shè)計(jì)者自己寫的底層事務(wù)處理代碼。 Transaction接口是對(duì)實(shí)際事務(wù)實(shí)現(xiàn)的一個(gè)抽象,這些實(shí)現(xiàn)包括JDBC的事務(wù)、JTA中的UserTransaction、甚至可以是CORBA事務(wù)。之所以這樣設(shè)計(jì)是能讓開發(fā)者能夠使用一個(gè)統(tǒng)一事務(wù)的操作界面,使得自己的項(xiàng)目可以在不同的環(huán)境和容器之間方便地移值。
Query和Criteria接口
Query接口讓你方便地對(duì)數(shù)據(jù)庫及持久對(duì)象進(jìn)行查詢,它可以有兩種表達(dá)方式:HQL語言或本地?cái)?shù)據(jù)庫的SQL語句。Query經(jīng)常被用來綁定查詢參數(shù)、限制查詢記錄數(shù)量,并最終執(zhí)行查詢操作。
Criteria接口與Query接口非常類似,它允許你創(chuàng)建并執(zhí)行面向?qū)ο蟮臉?biāo)準(zhǔn)化查詢。
值得注意的是Query接口也是輕量級(jí)的,它不能在Session之外使用。
Callback 接口
當(dāng)一些有用的事件發(fā)生時(shí)――例如持久對(duì)象的載入、存儲(chǔ)、刪除時(shí),Callback接口會(huì)通知Hibernate去接收一個(gè)通知消息。一般而言,Callback接口在用戶程序中并不是必須的,但你要在你的項(xiàng)目中創(chuàng)建審計(jì)日志時(shí),你可能會(huì)用到它。
一個(gè)重要的術(shù)語:Type
Hibernate的設(shè)計(jì)者們發(fā)明了一個(gè)術(shù)語:Type,它在整個(gè)構(gòu)架中是一個(gè)非;A(chǔ)、有著強(qiáng)大功能的元素。一個(gè)Type對(duì)象能將一個(gè)Java類型映射到數(shù)據(jù)庫中一個(gè)表的字段中去(實(shí)際上,它可以映射到表的多個(gè)字段中去)。持久類的所有屬性都對(duì)應(yīng)一個(gè)type。這種設(shè)計(jì)思想使用Hibernate有著高度的靈活性和擴(kuò)展性。
Hibernate內(nèi)置很多type類型,幾乎包括所有的Java基本類型,例如Java.util.Currency、Java.util.calendar、byte[]和Java.io.Serializable。
不僅如此,Hibernate還支持用戶自定義的type,通過實(shí)現(xiàn)接口UserType和接口CompositeUserType,你可以加入自己的type。你可以利用這種特色讓你的項(xiàng)目中使用自定義的諸如Address、Name這樣的type,這樣你就可以獲得更大的便利,讓你的代碼更優(yōu)雅。自定義type在Hibernate中是一項(xiàng)核心特色,它的設(shè)計(jì)者鼓勵(lì)你多多使用它來創(chuàng)建一個(gè)靈活、優(yōu)雅的項(xiàng)目!
策略接口
Hibernate與某些其它開源軟件不同的還有一點(diǎn)――高度的可擴(kuò)展性,這通過它的內(nèi)置策略機(jī)制來實(shí)現(xiàn)。當(dāng)你感覺到Hibernate的某些功能不足,或者有某些缺陷時(shí),你可以開發(fā)一個(gè)自己的策略來替換它,而你所要做的僅僅只是繼承它的某個(gè)策略接口,然后實(shí)現(xiàn)你的新策略就可以了,以下是它的策略接口:
· 主鍵的生成 (IdentifierGenerator 接口)
· 本地SQL語言支持 (Dialect 抽象類)
· 緩沖機(jī)制 (Cache 和CacheProvider 接口)
· JDBC 連接管理 (ConnectionProvider接口)
· 事務(wù)管理 (TransactionFactory, Transaction, 和 TransactionManagerLookup 接口)
· ORM 策略 (ClassPersister 接口)
· 屬性訪問策略 (PropertyAccessor 接口)
· 代理對(duì)象的創(chuàng)建 (ProxyFactory接口)
Hibernate為以上所列的機(jī)制分別創(chuàng)建了一個(gè)缺省的實(shí)現(xiàn),因此如果你只是要增強(qiáng)它的某個(gè)策略的功能的話,只需簡單地繼承這個(gè)類就可以了,沒有必要從頭開始寫代碼。
以上就是Hibernate的一些核心接口,但當(dāng)我們真正開始用它進(jìn)行開發(fā)時(shí),你的腦海里可能總會(huì)有一個(gè)疑問:我是通過什么方式,并從哪里取得Session的呢?以下我們就解答這個(gè)問題。
基礎(chǔ)配置
現(xiàn)在回顧一下我們先前的內(nèi)容:我們寫出了一個(gè)示例程序,并簡要地講解了Hibernate的一些核心類。但要真正使你的項(xiàng)目運(yùn)行起來,還有一件事必須要做:配置。Hibernate可以配置成可在任何Java環(huán)境中運(yùn)行,一般說來,它通常被用在2-3層的C/S模式的項(xiàng)目中,并被部署在服務(wù)端。在這種項(xiàng)目中,Web瀏覽器、或Java GUI程序充當(dāng)者客戶端。盡管我們的焦點(diǎn)主要是集中在多層web應(yīng)用,但實(shí)際上在一些基于命令行的應(yīng)用中也可以使用Hibernate。并且,對(duì)Hibernate的配置在不同的環(huán)境下都會(huì)不同,Hibernate運(yùn)行在兩種環(huán)境下:可管理環(huán)境和不可管理環(huán)境
· 可管理環(huán)境――這種環(huán)境可管理如下資源:池資源管理,諸如數(shù)據(jù)庫連接池和,還有事務(wù)管理、安全定義。一些典型的J2EE服務(wù)器(JBoss、Weblogic、WebSphere)已經(jīng)實(shí)現(xiàn)了這些。
· 不可管理環(huán)境――只是提供了一些基本的功能,諸如像Jetty或Tomcat這樣的servlet容器環(huán)境。一個(gè)普通的Java桌面應(yīng)用或命令行程序也可以認(rèn)為是處于這種環(huán)境下。這種環(huán)境不能提供自動(dòng)事務(wù)處理、資源管理或安全管理,這些都必須由應(yīng)用程序自己來定義。
Hibernate的設(shè)計(jì)者們將這兩種環(huán)境設(shè)計(jì)了一個(gè)統(tǒng)一的抽象界面,因此對(duì)于開發(fā)者來說只有一種環(huán)境:可管理環(huán)境。如果實(shí)際項(xiàng)目是建立在諸如Tomcat這類不可管理的環(huán)境中時(shí),那Hibernate將會(huì)使用它自己的事務(wù)處理代碼和JDBC連接池,使其變?yōu)橐粋(gè)可管理環(huán)境。
對(duì)于可管理的環(huán)境而言,Hibernate會(huì)將自己集成在這種環(huán)境中。對(duì)于開發(fā)者而言,你所要做的工作非常簡單:只需從一個(gè)Configuration類中創(chuàng)建一個(gè)SessionFactory類就可以了。
創(chuàng)建一個(gè)SessionFactory對(duì)象
為了能創(chuàng)建一個(gè)SessionFactory對(duì)象,你必須在Hibernate初始化時(shí)創(chuàng)建一個(gè)Configuration類的實(shí)例,并將已寫好的映射文件交由它處理。這樣,Configuration對(duì)象就可以創(chuàng)建一個(gè)SessionFactory對(duì)象,當(dāng)SessionFactory對(duì)象創(chuàng)建成功后,Configuration對(duì)象就沒有用了,你可以簡單地拋棄它。如下是示例代碼:
Configuration cfg = new Configuration();
cfg.addResource("hello/Message.hbm.xml");
cfg.setProperties( System.getProperties() );
SessionFactory sessions = cfg.buildSessionFactory();
在以上代碼中,Message.hb.xml這個(gè)映射文件的位置比較特殊,它與當(dāng)前的classpath相關(guān)。例如classpath包含當(dāng)前目錄,那在上述代碼中的Message.hbm.xml映射文件就可以保存在當(dāng)前目錄下的hello目錄中。
作為一種約定,Hibernate的映射文件默認(rèn)以.htm.xml作為其擴(kuò)展名。另一個(gè)約定是堅(jiān)持為每一個(gè)持久類寫一個(gè)配置文件,想一想如果你將所有持久類的映射寫入一個(gè)單獨(dú)的配置文件中的話,那這個(gè)配置文件肯定非常龐大,不易維護(hù)。但這里又出現(xiàn)了一個(gè)新問題:如果為每個(gè)類寫一個(gè)配置文件的話,這么多的配置文件應(yīng)該存放在哪里呢?
Hibernate推薦你將每個(gè)映射文件保存在與持久類相同的目錄下,并且與持久類同名。例如我們第一個(gè)示例程序中的Message持久類放在hello目錄下,那你必須在這個(gè)目錄下存放名為Message.hbm.xml的映射文件。這樣一個(gè)持久類都有自己的一個(gè)映射文件,避免了出現(xiàn)像struts項(xiàng)目中的“struts-config.xml地獄”的情況。如果你不遵循這種規(guī)定,那你必須手動(dòng)地用addResource()方法將一個(gè)個(gè)的映射文件載入;但你如果遵循這種規(guī)定,那你可以方便地用addClass()方法同時(shí)將持久類和它的映射文件載入,以下是體現(xiàn)這種便利性的示例代碼:
SessionFactory sessions = new Configuration()
.addClass(org.hibernate.auction.model.Item.class)
.addClass(org.hibernate.auction.model.Category.class)
.addClass(org.hibernate.auction.model.Bid.class)
.setProperties( System.getProperties() )
.buildSessionFactory();
當(dāng)然,Hibernate的映射文件還有很多其它的配置選項(xiàng),比如數(shù)據(jù)庫連接的設(shè)定,或是能夠改變Hibernate運(yùn)行時(shí)行為的一些設(shè)定。所有的設(shè)置可能是非常龐雜的,足以讓你喘不過氣來,但是不必?fù)?dān)心,因?yàn)镠ibernate為絕大多數(shù)值都設(shè)定了一個(gè)合理缺省值,你只需要修改這些配置文件中的極小一部分值。
你可以通過以下幾種方式來修改Hibernate的系統(tǒng)配置參數(shù):
· 將一個(gè)Java.util.Properties實(shí)例作為參數(shù)傳給Configuration類的setProperties()方法。
· 在Hibernate啟動(dòng)時(shí)用Java –Dproperty=value的方式設(shè)置值。
· 在classpath可以找到的路徑下創(chuàng)建一個(gè)名為hibernate.properties的配置文件。
· 在classpath可以找到的路徑下創(chuàng)建一個(gè)名為hibernate.cfg.xml的文件,并在其<property>標(biāo)簽中定義屬性值。
以上就是對(duì)Hibernate的一個(gè)大致介紹,如果你想知道得更多,那本文還是遠(yuǎn)遠(yuǎn)不夠的,我將陸續(xù)推出更多關(guān)于Hibernate的資料。但有一點(diǎn)是毫無疑問的:它的確是一個(gè)非常優(yōu)秀的持久層解決方案!
<>