Hibernate第一次课(2)---Hibernate原理简介
學(xué)員要求:熟悉Java、SQL、JDBC,掌握面向?qū)ο蟮拈_發(fā)方法,并有實(shí)際的項(xiàng)目開發(fā)經(jīng)驗(yàn)。
培訓(xùn)目標(biāo):讓學(xué)員了解O/R Mapping原理,掌握Hibernate開發(fā)的相關(guān)知識(shí),并能使用Hibernate進(jìn)行實(shí)際項(xiàng)目開發(fā)。
(讓學(xué)員理解典型的三層架構(gòu),如何用O/R Mapping框架來實(shí)現(xiàn)我們的數(shù)據(jù)層。這里主要介紹現(xiàn)在非常流程的Hibernate框架,希望通過培訓(xùn)之后,(學(xué)員了解Hibernate的架構(gòu),掌握Hibernate相關(guān)的概念;并教學(xué)員如何做對象和關(guān)系的映射,如何在應(yīng)用中使用Hibernate)
數(shù)據(jù)源層-O/R Mapping
主要介紹三層架構(gòu),如何分層?(邏輯上的分層,二個(gè)原則)
數(shù)據(jù)層技術(shù)的選擇:直接使用
SQL/JDBC:
優(yōu)點(diǎn):很多開發(fā)者熟悉關(guān)系數(shù)據(jù)庫管理系統(tǒng),理解SQL,也知道如何使用表和外鍵進(jìn)行工作。此外,他們可以始終使用眾所周知并廣泛使用的DAO設(shè)計(jì)模式對業(yè)務(wù)邏輯隱藏復(fù)雜的JDBC代碼和不可移植的SQL。
缺點(diǎn):為域中的每個(gè)類手工編寫持續(xù)性代碼的工作是非常可觀的,特別是需要支持多種SQL方言時(shí)。這項(xiàng)工作通常會(huì)消耗很大一部分的開發(fā)努力。此外,當(dāng)需求改變時(shí),一個(gè)手工編碼的解決方案總是需要更多的注意和維護(hù)努力。
序列化:Java有一個(gè)內(nèi)建的持久化機(jī)制:序列化提供了將對象圖(應(yīng)用狀態(tài))寫到字節(jié)流中的能力,然后它可能被持久化到文件或數(shù)據(jù)庫中。持久化也被Java的遠(yuǎn)程方法調(diào)用(RMI)使用來為復(fù)雜對象傳遞值語義。持久化的另一種用法是在機(jī)器集群中跨節(jié)點(diǎn)復(fù)制應(yīng)用狀態(tài)。
缺點(diǎn):很不幸,一個(gè)相互連接的對象圖在序列化之后只能被當(dāng)作一個(gè)整體訪問,如果不反序列化整個(gè)流就不可能從流中取出任何數(shù)據(jù)。這樣,結(jié)果字節(jié)流肯定會(huì)被認(rèn)為不適合進(jìn)行任意的檢索或聚合。甚至不可能獨(dú)立地訪問或更新一個(gè)單獨(dú)的對象或子圖。
非常明顯,因?yàn)楫?dāng)前特定的技術(shù),序列化不適合于作為高并發(fā)性的Web和企業(yè)應(yīng)用的持久化機(jī)制。在特定的環(huán)境中它被作為桌面應(yīng)用的適當(dāng)?shù)某志没瘷C(jī)制。
EJB entity beans
EJB1.1實(shí)體Bean在實(shí)踐中徹底地失敗了。EJB規(guī)范的設(shè)計(jì)缺陷阻礙了Bean管理的持續(xù)性(BMP)實(shí)體Bean有效地執(zhí)行。在EJB1.1許多明顯的缺陷被糾正之后,一個(gè)邊緣的稍微可接受的解決方案是容器管理的持續(xù)性(CMP)。然而,CMP并不能表示一種對象-關(guān)系不匹配的解決方案。
CMP缺點(diǎn):
¨? CMP實(shí)體Bean的粒度既太粗又太細(xì):CMP Bean與關(guān)系模型中的表是按照一對一的方式定義的。這樣,它們的粒度過粗,不能夠完全利用Java豐富的類型。
¨? 雖然EJB可以利用繼承實(shí)現(xiàn),但實(shí)體Bean并不支持多態(tài)的關(guān)聯(lián)和查詢
¨? 不管EJB規(guī)范所宣稱的目標(biāo),實(shí)體Bean實(shí)際上是不可移植的。CMP引擎的性能因廠商而異,并且映射元數(shù)據(jù)也是高度特定于廠商的。
¨? 實(shí)體Bean不可序列化。我們發(fā)現(xiàn)當(dāng)我們需要將數(shù)據(jù)傳輸?shù)竭h(yuǎn)程客戶層時(shí),我們必須定
義額外的數(shù)據(jù)傳輸對象(DTO,也被稱作值對象)
¨? 實(shí)體Bean必須依賴于EJB容器測試?yán)щy。
JDO、Object-oriented database systems
大多數(shù)面向?qū)ο蟮臄?shù)據(jù)庫系統(tǒng)對ODMG標(biāo)準(zhǔn)都提供了許多程度的支持,但據(jù)我們所知,還沒有完全的實(shí)現(xiàn)。此外,在規(guī)范發(fā)布以后的很多年,甚至到了3.0版,還是感覺不太成熟,并且缺乏很多有用的特征,特別是基于Java環(huán)境的。ODMG也不再活躍。最近,Java數(shù)據(jù)對象(JDO)規(guī)范(發(fā)表于2002年4月)揭開了新的可能性。JDO由面向?qū)ο髷?shù)據(jù)庫團(tuán)體的成員驅(qū)動(dòng),除了對現(xiàn)有的ODMG的支持之外,面向?qū)ο蟮臄?shù)據(jù)庫產(chǎn)品現(xiàn)在還經(jīng)常將其作為主要的API采用。
JDO 的優(yōu)點(diǎn)在于它很簡單。開發(fā)人員使用 Java 語言持久存儲(chǔ)對象實(shí)例并從存儲(chǔ)器檢索實(shí)例。處理邏輯、同步和故障轉(zhuǎn)移等均被透明地處理。開發(fā)人員無需使用 SQL 或 Java 語言提供的不便的序列化機(jī)制,只使用 POJO(無格式普通 Java 對象)即可,利用 JDO 接口將對象引用傳遞到存儲(chǔ)器中并從存儲(chǔ)器檢索對象引用。
O/R Mapping
什么是O/R Mapping?它有什么優(yōu)點(diǎn)?
簡單地說,對象-關(guān)系映射就是Java應(yīng)用中的對象到關(guān)系數(shù)據(jù)庫中的表的自動(dòng)的(和透明的)持久化,使用元數(shù)據(jù)(meta data)描述對象與數(shù)據(jù)庫間的映射。本質(zhì)上,ORM的工作是將數(shù)據(jù)從一種表示(雙向)轉(zhuǎn)換為另一種。
提高生產(chǎn)率(Productivity)
與持久性有關(guān)的代碼可能是Java應(yīng)用中最乏味的代碼。Hibernate去掉了很多讓人心煩的工作(多于你的期望),讓你可以集中更多的精力到業(yè)務(wù)問題上。不論你喜歡哪種應(yīng)用開發(fā)策略——自頂向下,從域模型開始;或者自底向上,從一個(gè)現(xiàn)有的數(shù)據(jù)庫模式開始——使用Hibernate和適當(dāng)?shù)墓ぞ邔?huì)減少大量的開發(fā)時(shí)間。
可維護(hù)性(Maintainability)
?? 減少了代碼,重構(gòu)更方便,提高了可維護(hù)性。ORM是對象和關(guān)系數(shù)據(jù)庫之間的緩沖區(qū),用來很好的將他們隔離。
更好性能(Performance)
ORM軟件的實(shí)現(xiàn)人員可能有比你更多的時(shí)間來研究性能優(yōu)化問題。你知道嗎,例如,緩存PreparedStatement的實(shí)例對DB2的JDBC驅(qū)動(dòng)導(dǎo)致了一個(gè)明顯的性能增長但卻破壞了InterBase的JDBC驅(qū)動(dòng)?你了解嗎,對某些數(shù)據(jù)庫只更新一個(gè)表中被改變的字段可能會(huì)非常快但潛在地對其它的卻很慢?在你手工編寫的解決方案中,對這些不同策略之間的沖突進(jìn)行試驗(yàn)是多么不容易呀?
廠商獨(dú)立性(Vendor independence)
ORM抽象了你的應(yīng)用使用下層SQL數(shù)據(jù)庫和SQL方言的方式。如果工具支持許多不同的數(shù)據(jù)庫(dialect),那么這會(huì)給你的應(yīng)用帶來一定程度的可移植性。你不必期望可以達(dá)到“一次編寫,到處運(yùn)行”,因?yàn)閿?shù)據(jù)庫的性能不同并且達(dá)到完全的可移植性需要犧牲更強(qiáng)大的平臺(tái)的更多的力氣。然而,使用ORM開發(fā)跨平臺(tái)的應(yīng)用通常更容易。即使你不需要跨平臺(tái)操作,ORM依然可以幫你減小被廠商鎖定的風(fēng)險(xiǎn)。另外,數(shù)據(jù)庫獨(dú)立性對這種開發(fā)情景也有幫助:開發(fā)者使用一個(gè)輕量級的本地?cái)?shù)據(jù)庫進(jìn)行開發(fā)但實(shí)際產(chǎn)品需要配置在一臺(tái)不同的數(shù)據(jù)庫上。
如何做對象-關(guān)系數(shù)據(jù)庫映射?(最后引入Hibernate)
public class User {
?????? private Long id;
?????? private String name;
?????? private List address;
………
}
create table tbl_user (
?????? id bigint not null auto_increment,
?????? name varchar(255),
?????? primary key (id)
)
Java | 數(shù)據(jù)庫 |
| 類的屬性(基本類型) | 表的列 |
| 類 | 表 |
| 1:n/n:1 | 外鍵 |
| n:m | 關(guān)聯(lián)表 |
| 繼承 | 單表繼承、具體表繼承、類表繼承 |
1、? Java基本類型-表的
2、? Java類的映射
3、? 關(guān)聯(lián)的映射:例如一個(gè)User有多個(gè)Address,User和Address管理,User刪除時(shí),相應(yīng)的Address也應(yīng)該刪除。
對象-關(guān)系的不匹配范式(paradigm)
1、? 粒度(granularity)的問題。
增加一種新的數(shù)據(jù)類型,將Java地址對象在我們的數(shù)據(jù)庫中保存為單獨(dú)的一列,聽起來好像是最好的方法。畢竟,Java中的一個(gè)新的地址類與SQL數(shù)據(jù)類型中的一個(gè)新的地址類型可以保證互用性。然而,如果你檢查現(xiàn)在的數(shù)據(jù)庫管理系統(tǒng)對用戶定義列類型(UDT)的支持,你將會(huì)發(fā)現(xiàn)各種各樣的問題。
2、? 子類型(subtypes)的問題。
?? 子類型不匹配是指Java模型中的繼承結(jié)構(gòu)必須被持續(xù)化到SQL數(shù)據(jù)庫中,而SQL數(shù)
據(jù)庫并沒有提供一個(gè)支持繼承的策略。如何解決多態(tài)?
3、? 同一性(identity)的問題
Java對象定義了兩種不同的相等性的概念:
■ 對象同一性(粗略的等同于內(nèi)存位置的相等,使用a==b檢查)
■ 通過equals()方法的實(shí)現(xiàn)來決定的相等性(也被稱作值相等)
另一方面,數(shù)據(jù)庫行的同一性使用主鍵值表示。主鍵既不必然地等同于“equals()”也不等同于“==”。它通常是指幾個(gè)對象(不相同的)同時(shí)表示了數(shù)據(jù)庫中相同的行。而且,為一個(gè)持續(xù)類正確地實(shí)現(xiàn)equals()方法包含許多微妙的難點(diǎn)。
4、? 與關(guān)聯(lián)(associations)有關(guān)的問題
面向?qū)ο蟮恼Z言使用對象引用和對象引用的集合表示關(guān)聯(lián)。在關(guān)系世界里,關(guān)聯(lián)被表示為外鍵列,外鍵是幾個(gè)表的鍵值的拷貝。這兩種表示之間有些微妙的不同。
5、? 對象結(jié)構(gòu)導(dǎo)航的問題
在Java中訪問對象的方式與在關(guān)系數(shù)據(jù)庫中有根本的不同。在Java中,訪問用戶的賬單信息時(shí),你調(diào)用aUser.getBillingDetails().getAccountNumber()。這是最自然的面向?qū)?/p>
象數(shù)據(jù)的訪問方式,通常被形容為遍歷對象圖。根據(jù)實(shí)例間的關(guān)聯(lián),你從一個(gè)對象導(dǎo)航到另
一個(gè)對象。不幸地是,這不是從SQL數(shù)據(jù)庫中取出數(shù)據(jù)的有效方式。
為了提高數(shù)據(jù)訪問代碼的性能,唯一重要的事是最小化數(shù)據(jù)庫請求的次數(shù)。最明顯的方
式是最小化SQL查詢的數(shù)量(其它方式包括使用存儲(chǔ)過程或者JDBC批處理API)。
使用SQL有效地訪問關(guān)系數(shù)據(jù)通常需要在有關(guān)的表之間使用連接。在連接中包含的
表的數(shù)量決定了你可以導(dǎo)航的對象圖的深度。
性能:N+1的問題
范式不匹配的代價(jià):
1、花費(fèi)很多時(shí)間和精力來手工解決對象和關(guān)系的不匹配。
2、為了解決不匹配,甚至要扭曲對象模型直到它與下層的關(guān)系技術(shù)匹配為止
4、? JDBC API本身的問題。JDBC和SQL提供了一個(gè)面向語句(即命令)的方法從SQL數(shù)據(jù)庫中來回移動(dòng)數(shù)據(jù)。至少在三個(gè)時(shí)刻(Insert,Update,Select)必須指定一個(gè)結(jié)構(gòu)化關(guān)系,這增加了設(shè)計(jì)和實(shí)現(xiàn)所需要的時(shí)間。
主流持久層框架縱覽
目前眾多廠商和開源社區(qū)都提供了持久層框架實(shí)現(xiàn),常見的有:
Apache OJB(http://db.apache.org/ojb/ )
Cayenne(http://objectstyle.org/cayenne/ )
Jaxor(http://jaxor.sourceforge.net )
Hibernate(http://www.hibernage.org)
iBATIS(http://www.ibatis.com )
jRelationalFramework(http://jrf.sourceforge.net)
mirage(http://itor.cq2.org/en/oss/mirage/toon)
SMYLE(http://www.drjava.de/smyle/)
TopLink(http://otn.oracle.com/products/ias/toplink/index.html )
(其中TopLink 是Oracle 的商業(yè)產(chǎn)品。其他均為開源項(xiàng)目)
Apache OJB 的優(yōu)勢在于對各種標(biāo)準(zhǔn)的全面支持(不過事實(shí)上,我們的系統(tǒng)研發(fā)中并
不需要同時(shí)支持這么多標(biāo)準(zhǔn),追求多種標(biāo)準(zhǔn)的并行支持本身也成為Apache OJB 項(xiàng)目發(fā)
展的沉重包袱),且其從屬于Apache 基金組織,有著可靠的質(zhì)量保證和穩(wěn)定的發(fā)展平臺(tái)。
Hibernate 在2003 年末被JBoss 組織收納,成為從屬于JBoss 組織的子項(xiàng)目之一,
從而贏得了良好的發(fā)展前景(同時(shí)榮獲Jolt 2004 大獎(jiǎng))。
Hibernate 與OJB 設(shè)計(jì)思想類似,具備相近的功能和特色,但由于其更加靈活快速
的發(fā)展策略,得到了廣大技術(shù)人員的熱情參與,因此也得到了更廣泛的推崇。相對Apache
OJB 遲鈍的項(xiàng)目開發(fā)進(jìn)度表,Hibernate 活躍的開發(fā)團(tuán)隊(duì)以及各社區(qū)內(nèi)對其熱烈的關(guān)注為
其帶來了極大的活力,并逐漸發(fā)展成Java 持久層事實(shí)上的標(biāo)準(zhǔn)。
iBATIS 相對Apache OJB 和Hibernate 項(xiàng)目則另具特色,iBATIS 采取了更加開放式
的設(shè)計(jì),通過iBATIS,我們可以控制更多的數(shù)據(jù)庫操作細(xì)節(jié)。相對而言,Hibernate、
Apache OJB 對持久層的設(shè)計(jì)則較為封閉,封閉化的設(shè)計(jì)對持久層進(jìn)行了較為徹底的封
裝,從而將底層細(xì)節(jié)與上層架構(gòu)完全分離,大多數(shù)情況下,特別是對于新系統(tǒng),新產(chǎn)品
的研發(fā)而言,封閉化的設(shè)計(jì)帶來了更高的開發(fā)效率和更好的封裝機(jī)制,但是在某些情況
下,卻又為一些必須的底層調(diào)整帶來了阻力,如在對遺留系統(tǒng)的改造和對既有數(shù)據(jù)庫的
復(fù)用上,表現(xiàn)出靈活性不足的弱點(diǎn)。此時(shí)作為OJB,Hibernate 的一個(gè)有益補(bǔ)充,iBATIS
的出現(xiàn)顯得別具意義。
Hibernate入門
Hibernate概述
Hibernate是非常優(yōu)秀、成熟的O/R Mapping框架。它提供了強(qiáng)大、高性能的Java對象和關(guān)系數(shù)據(jù)的持久化和查詢功能。
(O/R Mapping是一項(xiàng)實(shí)用的工程技術(shù),把數(shù)據(jù)庫的E/R模型用java的OO語法描述出來,Hibernate是其中的當(dāng)之無愧的最耀眼的明星,cglib動(dòng)態(tài)增強(qiáng),多種靈活的class繼承樹映射機(jī)制,廣泛的社團(tuán)支援,掩蓋了其他項(xiàng)目的光輝。)
Hibernate的優(yōu)勢
¨? 開源(LGPL)
¨? 成熟
¨? 流行(約13 000 downloads/month)
¨? 自定義API
JBoss 將用Hibernate3實(shí)現(xiàn)Entity Beans
使用Hibernate的開發(fā)步驟
1、? 設(shè)計(jì)
一般首先進(jìn)行領(lǐng)域?qū)ο蟮脑O(shè)計(jì)。因?yàn)樵贖ibernate中,我們的領(lǐng)域?qū)ο罂梢灾苯映洚?dāng)持久化類。
2、? 映射
定義Hibernate的映射文件,實(shí)現(xiàn)持久化類和數(shù)據(jù)庫之間映射。
3、? 應(yīng)用
使用Hibernate提供的API,實(shí)現(xiàn)具體的持久化業(yè)務(wù)。
Hibernate的映射
Entity-hbm-ddl(數(shù)據(jù)庫)(hbm(hibernate mapping)和ddl(Data Definition Language)的全稱)
『之間的互相轉(zhuǎn)換』
User.java User.hbm.xml
XDoclet:它通過在Java源代碼中加入特定的JavaDoc tag,從而為其添加特定的附加語義,之后通過XDoclet工具對代碼中JavaDoc Tag進(jìn)行分析,自動(dòng)生成與代碼對應(yīng)的配置文件(http://xdoclet.sourceforge.net/)。XDoclet提供了對Hibernate的支持,這樣我們可以直接由Java代碼生成Hibernate映射文件。
Middlegen: 用來從數(shù)據(jù)庫中已有的表結(jié)構(gòu)中生成Hibernate映射文件。當(dāng)前版本是2.1可以去http://boss.bekk.no/boss/middlegen下載。
Hibernate核心接口
Configuration:
正如其名,Configuration 類負(fù)責(zé)管理Hibernate 的配置信息。Hibernate 運(yùn)行時(shí)需要
獲取一些底層實(shí)現(xiàn)的基本信息,其中幾個(gè)關(guān)鍵屬性包括:
1、數(shù)據(jù)庫URL
2、數(shù)據(jù)庫用戶
3、數(shù)據(jù)庫用戶密碼
4、數(shù)據(jù)庫JDBC驅(qū)動(dòng)類
5、? 數(shù)據(jù)庫dialect,用于對特定數(shù)據(jù)庫提供支持,其中包含了針對特定數(shù)據(jù)庫特性的實(shí)現(xiàn),如Hibernate數(shù)據(jù)類型到特定數(shù)據(jù)庫數(shù)據(jù)類型的映射等。
當(dāng)然,還有指定Hibernate映射文件的位置。(*.hbm.xml)。
Hibernate配置有兩種方法:
一、屬性文件配置。默認(rèn)文件名是hibernate.properties。調(diào)用代碼:
??? Configuration config = new Configuration();
二、XML文件配置。默認(rèn)文件名是hibernate.cfg.xml。
Configuration config = new Configuration().configure();
SessionFactory:應(yīng)用程序從SessionFactory(會(huì)話工廠)里獲得Session(會(huì)話)實(shí)例。它打算在多個(gè)應(yīng)用線程間進(jìn)行共享。通常情況下,整個(gè)應(yīng)用只有唯一的一個(gè)會(huì)話工廠——例如在應(yīng)用初始化時(shí)被創(chuàng)建。然而,如果你使用Hibernate訪問多個(gè)數(shù)據(jù)庫,你需要對每一個(gè)數(shù)據(jù)庫使用一個(gè)會(huì)話工廠。
會(huì)話工廠緩存了生成的SQL語句和Hibernate在運(yùn)行時(shí)使用的映射元數(shù)據(jù)。它也保存了在一個(gè)工作單元中讀入的數(shù)據(jù)并且可能在以后的工作單元中被重用(只有類和集合映射指定了使用這種二級緩存時(shí)才會(huì)如此)。
SessionFactory sessionFactory = config.buildSessionFactory();
Session(會(huì)話):該接口是Hibernate使用最多的接口。Session不是線程安全的,它代表與數(shù)據(jù)庫之間的一次操作。Session通過SessionFactory打開,在所有的工作完成后,需要關(guān)閉:它的概念介于Connection和Transaction之間。我們可以簡單的認(rèn)為它是已經(jīng)裝載對象的緩存或集合的一個(gè)獨(dú)立工作單元。
我們有時(shí)也稱Session為持久化管理器,因?yàn)樗桥c持久化有關(guān)的操作的接口。
Hibernate會(huì)話并不是線程安全的因此應(yīng)該被設(shè)計(jì)為每次只能在一個(gè)線程中使用。Hibernate會(huì)話與Web層的HttpSession沒有任何關(guān)系。
Session session = sessionFactory.openSession();
Transaction:事務(wù)將應(yīng)用代碼從底層的事務(wù)實(shí)現(xiàn)中抽象出來——這可能是一個(gè)JDBC事務(wù),一個(gè)JTA用戶事務(wù)或者甚至是一個(gè)公共對象請求代理結(jié)構(gòu)(CORBA)——允許應(yīng)用通過一組一致的API控制事務(wù)邊界。這有助于保持Hibernate應(yīng)用在不同類型的執(zhí)行環(huán)境或容器中的可移植性。
Transaction trans = session.beginTransaction ();
Query: Query(查詢)接口允許你在數(shù)據(jù)庫上執(zhí)行查詢并控制查詢?nèi)绾螆?zhí)行。查詢語句使用HQL或者本地?cái)?shù)據(jù)庫的SQL方言編寫。
Query query = session.createQuery(“from User”);
Lifecycle:Lifecycle接口提供了一些回調(diào)方法,可以讓持久化對象在save或load之后,或者在delete或update之前進(jìn)行必要的初始化與清除步驟。
public interface Lifecycle {
??????? public boolean onSave(Session s) throws CallbackException;?? (1)
??????? public boolean onUpdate(Session s) throws CallbackException; (2)
??????? public boolean onDelete(Session s) throws CallbackException; (3)
??????? public void onLoad(Session s, Serializable id);????????????? (4)
}
(1) onSave - 在對象即將被save或者insert的時(shí)候回調(diào)
?(2) onUpdate - 在對象即將被update的時(shí)候回調(diào)(也就是對象被傳遞給Session.update()的時(shí)候)
?(3) onDelete - 在對象即將被delete(刪除)的時(shí)候回調(diào)
?(4) onLoad - 在對象剛剛被load(裝載)后的時(shí)候回調(diào)
Validatable: 該接口是合法性檢查的回調(diào)。如果持久化類需要在保存其持久化狀態(tài)前進(jìn)行合法性檢查,它可以實(shí)現(xiàn)下面的接口:
public interface Validatable {
??????? public void validate() throws ValidationFailure;
}
如果發(fā)現(xiàn)對象違反了某條規(guī)則,應(yīng)該拋出一個(gè)ValidationFailure異常。在Validatable實(shí)例的validate()方法內(nèi)部不應(yīng)該改變它的狀態(tài)。
和Lifecycle接口的回調(diào)方法不同,validate()可能在任何時(shí)間被調(diào)用。應(yīng)用程序不應(yīng)該把validate()調(diào)用和商業(yè)功能聯(lián)系起來。
Interceptor: Interceptor接口提供從session到你的應(yīng)用程序的回調(diào)方法,讓你的程序可以觀察和在持久化對象保存/更改/刪除或者裝載的時(shí)候操作它的屬性。一種可能的用途是用來監(jiān)視統(tǒng)計(jì)信息。比如,下面的Interceptor會(huì)自動(dòng)在一個(gè)Auditable創(chuàng)建的時(shí)候設(shè)置其createTimestamp,并且當(dāng)它被更改的時(shí)候,設(shè)置其lastUpdateTimestamp屬性。
UserType: 開發(fā)者創(chuàng)建屬于他們自己的值類型也是很容易的。比如說,你可能希望持久化java.lang.BigInteger類型的屬性,持久化成為VARCHAR字段。Hibernate沒有內(nèi)置這樣一種類型。自定義類型能夠映射一個(gè)屬性(或集合元素)到不止一個(gè)數(shù)據(jù)庫表字段。比如說,你可能有這樣的Java屬性:getName()/setName(),這是java.lang.String類型的,對應(yīng)的持久化到三個(gè)字段:FIRST_NAME, INITIAL, SURNAME。 要實(shí)現(xiàn)一個(gè)自定義類型,可以實(shí)現(xiàn)net.sf.hibernate.UserType或net.sf.hibernate.CompositeUserType中的任一個(gè),并且使用類型的Java全限定類名來聲明屬性。請查看net.sf.hibernate.test.DoubleStringType這個(gè)例子,看看它是怎么做的。
<property name="twoStrings" type="net.sf.hibernate.test.DoubleStringType">
??? <column name="first_string"/>
??? <column name="second_string"/>
</property>
注意使用<column>標(biāo)簽來把一個(gè)屬性映射到多個(gè)字段的做法。
用戶的例子
設(shè)計(jì):用戶,id name
映射:User.java User.hbm.xml
一、安裝
二、持久化類(Persistent Class)
持久化類不需要實(shí)現(xiàn)什么特別的接口,也不需要從一個(gè)特別的持久化根類繼承下來。Hibernate也不需要使用任何編譯期處理,比如字節(jié)碼增強(qiáng)操作,它獨(dú)立的使用Java反射機(jī)制和運(yùn)行時(shí)類增強(qiáng)(通過CGLIB)。所以,在Hibernate中,POJO的類不需要任何前提條件,我們就可以把它映射成為數(shù)據(jù)庫表。
持久化類必須遵循的原則:
1、? 為類的持久化類字段申明訪問方法(Get/set)。Hibernate對JavaBeans風(fēng)格的屬性實(shí)行持久化。
2、? 實(shí)現(xiàn)一個(gè)默認(rèn)的構(gòu)造方法(constructor)。這樣的話Hibernate就可以使用Constructor.newInstance()來實(shí)例化它們。
3、? 如果是集合類型的屬性,它的類型必須定義為集合的接口。例如:List、Set
4、? 提供一個(gè)標(biāo)識(shí)屬性(identifier property)。如果沒有該屬性,一些功能不起作用,比如:級聯(lián)更新(Cascaded updates)Session.saveOrUpdate()。
三、hibernate映射文件
四、應(yīng)用:TestUser.java
之后做個(gè)總結(jié),特別是CRUD操作。
Hibernate映射聲明(Mapping declaration)
一、???????????? DOCTYPE聲明。
一個(gè)XML document應(yīng)該在文檔的起始位置有一個(gè)XML的聲明,可能跟隨著一個(gè)DOCTYPE的聲明。一個(gè)DOCTYPE聲明告訴一個(gè)XML parser這個(gè)XML文檔遵循了哪一個(gè)DTD(Document Type Declaration)。Parser可以用此信息來確認(rèn)這個(gè)XML文檔包含的僅是這個(gè)DTD聲明的XML element。
例如:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
??????? "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
??????? "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
DTD可以從上述URL中獲取,或者在hibernate-x.x.x/src/net/sf/hibernate目錄中,或hibernate.jar文件中找到。Hibernate總是會(huì)在它的classptah中首先搜索DTD文件。
二、???????????? hibernate-mapping
它是文檔的根(root),可以包含多個(gè)類的映射,但一般只包含一個(gè)類。
<hibernate-mapping
???????? schema="schemaName"??????????????????? (1)
???????? default-cascade="none|save-update"???????? ??(2)
???????? auto-import="true|false"??????????????????? (3)
???????? package="package.name"?????????????????? (4)
?/>
(1)、schema(可選):數(shù)據(jù)庫Schema Name
(2)、default-cascade(可選,默認(rèn)為none):默認(rèn)的級聯(lián)風(fēng)格
(3)、auto-import(可選,默認(rèn)為true):是否允許在查詢語言中使用非完全限定的類名即只用類的名稱,不用加入包名(僅限本映射文件中定義的類)。
(4)、package(可選),如果該映射文件中定義的類名不包含package,則使用這里定義的package作為類名的前綴。
注:(3)默認(rèn)的值是“true”,如果有多個(gè)類的名字相同,則必須將該值設(shè)為false。
三、class
用class元素來定義一個(gè)持久化類。
<class
??????? name="ClassName"??????????????????????? (1)
??????? table="tableName"??????????????????????? (2)
??????? discriminator-value="discriminator_value"???? (3)
??????? mutable="true|false"?????????????????????? (4)
??????? schema="owner"????????????????????????? (5)
??????? proxy="ProxyInterface"??????????????????? ?(6)
??????? dynamic-update="true|false"???????????????? (7)
??????? dynamic-insert="true|false"????????????????? (8)
??????? select-before-update="true|false"???????????? (9)
??????? polymorphism="implicit|explicit"???????????? (10)
??????? where="arbitrary sql where condition"???????? (11)
??????? persister="PersisterClass"?? ????????????????(12)
??????? batch-size="N"?????????????????????????? (13)
??????? optimistic-lock="none|version|dirty|all"????? ??(14)
??????? lazy="true|false"???????????????????????? (15)
/>
1、? name:持久化類(或Java接口)的全名。
2、? table:對應(yīng)的數(shù)據(jù)庫表名。
3、? discriminator-value(鑒別值)(可選,默認(rèn)和類名一樣):一個(gè)用于區(qū)分不同子類的值,在多態(tài)行為中使用。
4、? mutable(可選,默認(rèn)值為true):表明該類是否可以改變。如果將它設(shè)為false,則應(yīng)用程序不能對此類對應(yīng)的數(shù)據(jù)進(jìn)行修改和刪除。
5、? schema(可選):覆蓋在根<hibernate-mapping>元素中指定的schema名字。
6、? proxy(可選):指定一個(gè)接口,在延遲裝載時(shí)作為代理使用。你可以在這里使用該類自己的名字。
7、? dynamic-update(動(dòng)態(tài)更新) (可選,默認(rèn)為false): 指定用于UPDATE 的SQL將會(huì)在運(yùn)行時(shí)動(dòng)態(tài)生成,并且只更新那些改變過的字段。
8、? dynamic-insert(動(dòng)態(tài)插入) (可選, 默認(rèn)為false): 指定用于INSERT的 SQL 將會(huì)在運(yùn)行時(shí)動(dòng)態(tài)生成,并且只包含那些非空值字段。
9、? select-before-update (可選,默認(rèn)值為false): 指定Hibernate除非確定對象的確被修改了,不會(huì)執(zhí)行SQL UPDATE操作。在特定場合(實(shí)際上,只會(huì)發(fā)生在一個(gè)臨時(shí)對象關(guān)聯(lián)到一個(gè)新的session中去,執(zhí)行update()的時(shí)候),這說明Hibernate會(huì)在UPDATE之前執(zhí)行一次額外的SQL SELECT操作,來決定是否應(yīng)該進(jìn)行UPDATE。
10、????????????? polymorphism(多形,多態(tài)) (可選, 默認(rèn)值為 implicit (隱式)): 界定是隱式還是顯式的使用查詢多態(tài)。
11、????????????? where (可選) 指定一個(gè)附加的SQLWHERE 條件,在抓取這個(gè)類的對象時(shí)會(huì)一直增加這個(gè)條件。
12、????????????? persister (可選): 指定一個(gè)定制的ClassPersister。
13、????????????? batch-size (可選,默認(rèn)是1) 指定一個(gè)用于根據(jù)標(biāo)識(shí)符抓取實(shí)例時(shí)使用的"batch size"(批次抓取數(shù)量)。
14、????????????? optimistic-lock(樂觀鎖定) (可選,默認(rèn)是version): 決定樂觀鎖定的策略。
15、????????????? lazy(延遲) (可選): 假若設(shè)置 lazy="true",就是設(shè)置這個(gè)類自己的名字作為proxy接口的一種等價(jià)快捷形式。
四、id
持久化類必須要聲明一個(gè)字段對應(yīng)數(shù)據(jù)庫表的主鍵。
<id
??????? name="propertyName"????????????????????? (1)
??????? type="typename"????????????????????????? (2)
??????? column="column_name"???????????????????? (3)
??????? unsaved-value="any|none|null|id_value"?? (4)
??????? access="field|property|ClassName">?????? (5)
??????? <generator class="generatorClass"/>
</id>
(1)、name(可選):標(biāo)識(shí)屬性的名稱。
(2)、type(可選):標(biāo)識(shí)Hibernate類型的名字。
(3)、column(可選-默認(rèn)為屬性名):對應(yīng)數(shù)據(jù)庫表的主鍵字段的名字。
(4)、unsaved-value(可選-默認(rèn)為null):這個(gè)值用來判斷對象是否要保存。如果一個(gè)對象id值與該值相等時(shí),Hibernate則會(huì)認(rèn)為該對象是一個(gè)新的對象,并沒有持據(jù)化到數(shù)據(jù)庫中。舉例:假如一個(gè)新建對象的屬性id的類型為int,我們知道如果不給id賦值,它默認(rèn)的值就應(yīng)該是“0”,如果這時(shí)unsaved-value是默認(rèn)的null。則當(dāng)保存這個(gè)新建對象,調(diào)用session. SaveOrUpdate()方法時(shí)會(huì)拋出異常。因?yàn)閕d的值不等于null,所以Hibernate會(huì)認(rèn)為該對象已經(jīng)保存,它會(huì)去執(zhí)行update操作。
Generator
主鍵生成器,每個(gè)主鍵都必須定義相應(yīng)的主鍵生成策略。它用來為持久化類實(shí)例生成唯一的標(biāo)識(shí)。例如:
<id name="id" type="long" column="uid" unsaved-value="0">
??????? <generator class="net.sf.hibernate.id.TableHiLoGenerator">
??????????????? <param name="table">uid_table</param>
??????????????? <param name="column">next_hi_value_column</param>
??????? </generator>
</id>
所有的生成器都實(shí)現(xiàn)net.sf.hibernate.id.IdentifierGenerator接口。這是一個(gè)非常簡單的接口;某些應(yīng)用程序可以選擇提供他們自己特定的實(shí)現(xiàn)。當(dāng)然,Hibernate提供了很多內(nèi)置的實(shí)現(xiàn)。
下面是一些內(nèi)置生成器的快捷名字:
1、? 數(shù)據(jù)庫提供的主鍵生成機(jī)制。identity、sequence、
2、? 外部程序提供的主鍵生成機(jī)制。increment ,hilo,seqhilo,uuid.hex,uuid.string
3、? 其它。native,assigned,foreign
increment(遞增):主鍵按數(shù)值順序遞增。此方式的實(shí)現(xiàn)機(jī)制為在當(dāng)前應(yīng)用實(shí)例中維持
一個(gè)變量,以保存著當(dāng)前的最大值,之后每次需要生成主鍵的時(shí)候?qū)⒋酥导?作為主鍵。用于為long, short或者int類型生成唯一標(biāo)識(shí)。只有在沒有其他進(jìn)程往同一張表中插入數(shù)據(jù)時(shí)才能使用。 在集群下不要使用。
identity
采用數(shù)據(jù)庫提供的主鍵生成機(jī)制(數(shù)據(jù)庫內(nèi)部支持標(biāo)識(shí)字段)。如DB2、SQL Server、MySQL中的主鍵生成機(jī)制。返回的標(biāo)識(shí)符是long, short 或者int類型的。
sequence (序列):采用數(shù)據(jù)庫提供的sequence 機(jī)制生成主鍵。如Oralce 中的Sequence。
hilo (高低位): 通過hi/lo算法實(shí)現(xiàn)的主鍵生成機(jī)制,需要額外的數(shù)據(jù)庫表保存主鍵生成歷史狀態(tài)。高/低位算法生成的標(biāo)識(shí)符只在一個(gè)特定的數(shù)據(jù)庫中是唯一的。在使用JTA獲得的連接或者用戶自行提供的連接中,不要使用這種生成器。
seqhilo(使用序列的高低位):與hilo 類似,通過hi/lo 算法實(shí)現(xiàn)的主鍵生成機(jī)制,只是主鍵歷史狀態(tài)保存在Sequence中,適用于支持Sequence的數(shù)據(jù)庫,如Oracle。
uuid.hex
用一個(gè)128-bit的UUID算法生成字符串類型的標(biāo)識(shí)符。在一個(gè)網(wǎng)絡(luò)中唯一(使用了IP地址,JVM的啟動(dòng)時(shí)間(精確到1/4秒),系統(tǒng)時(shí)間和一個(gè)計(jì)數(shù)器值(在JVM中唯一)。)。UUID被編碼為一個(gè)32位16進(jìn)制數(shù)字的字符串。
uuid.string
使用同樣的UUID算法。UUID被編碼為一個(gè)16個(gè)字符長的任意ASCII字符組成的字符串
native(本地)
根據(jù)底層數(shù)據(jù)庫的能力選擇identity, sequence 或者h(yuǎn)ilo中的一個(gè)
assigned(程序設(shè)置)
讓應(yīng)用程序在save()之前為對象分配一個(gè)標(biāo)示符。
foreign(外部引用)
使用另外一個(gè)相關(guān)聯(lián)的對象的標(biāo)識(shí)符。和<one-to-one>聯(lián)合一起使用。
五:property
<property>元素為類聲明了一個(gè)持久化的,JavaBean風(fēng)格的屬性。
<property
??????? name="propertyName"???????????????? (1)
??????? column="column_name"??????????????? (2)
??????? type="typename"???????????????????? (3)
??????? update="true|false"???????????????? (4)
??????? insert="true|false"???????????????? (4)
??????? formula="arbitrary SQL expression"? (5)
??????? access="field|property|ClassName"?? (6)
/>
(1) name: 屬性的名字,以小寫字母開頭。
(2) column (可選 - 默認(rèn)為屬性名字): 對應(yīng)的數(shù)據(jù)庫字段名。
(3) type (可選): 一個(gè)Hibernate類型的名字。
(4) update, insert (可選 - 默認(rèn)為 true) :表明在用于UPDATE 和/或 INSERT的SQL語句中是否包含這個(gè)字段。這二者如果都設(shè)置為false則表明這是一個(gè)“外源性(derived)”的屬性,它的值來源于映射到同一個(gè)(或多個(gè))字段的某些其他屬性,或者通過一個(gè)trigger(觸發(fā)器),或者其他程序。
(5) formula (可選): 一個(gè)SQL表達(dá)式,定義了這個(gè)計(jì)算(computed) 屬性的值。計(jì)算屬性沒有和它對應(yīng)的數(shù)據(jù)庫字段。
(6) access (可選 - 默認(rèn)值為 property): Hibernate用來訪問屬性值的策略。
六、多對一個(gè)(many-to-one)
<many-to-one
??????? name="propertyName"??????????????????????????????? (1)
??????? column="column_name"?????????????????????????????? (2)
??????? class="ClassName"????????????????????????????????? (3)
??????? cascade="all|none|save-update|delete"????????????? (4)
??????? outer-join="true|false|auto"?????????????????????? (5)
??????? update="true|false"??????????????????????????????? (6)
??????? insert="true|false"??????????????????????????????? (6)
??????? property-ref="propertyNameFromAssociatedClass"???? (7)
??????? access="field|property|ClassName"????????????????? (8)
/>
(1) name: 屬性名。
(2) column (可選): 字段名。
(3) class (可選 - 默認(rèn)是通過反射得到屬性類型): 關(guān)聯(lián)的類的名字。
(4) cascade(級聯(lián)) (可選): 指明哪些操作會(huì)從父對象級聯(lián)到關(guān)聯(lián)的對象。
(5) outer-join(外連接) (可選 - 默認(rèn)為 自動(dòng)): 當(dāng)設(shè)置hibernate.use_outer_join的時(shí)候,對這個(gè)關(guān)聯(lián)允許外連接抓取。
(6) update, insert (可選 - defaults to true) 指定對應(yīng)的字段是否在用于UPDATE 和/或 INSERT的SQL語句中包含。如果二者都是false,則這是一個(gè)純粹的“外源性(derived)”關(guān)聯(lián),它的值是通過映射到同一個(gè)(或多個(gè))字段的某些其他屬性得到的,或者通過trigger(觸發(fā)器),或者是其他程序。
(7) property-ref: (可選) 指定關(guān)聯(lián)類的一個(gè)屬性,這個(gè)屬性將會(huì)和本外鍵相對應(yīng)。如果沒有指定,會(huì)使用對方關(guān)聯(lián)類的主鍵。 該屬性只應(yīng)該用來對付老舊的數(shù)據(jù)庫系統(tǒng),可能出現(xiàn)外鍵指向?qū)Ψ疥P(guān)聯(lián)表的是個(gè)非主鍵字段(但是應(yīng)該是一個(gè)惟一關(guān)鍵字)的情況。
(8) access (可選 - 默認(rèn)是 property): Hibernate用來訪問屬性的策略。
七、一對多(one-to-many)
<set
??? name="propertyName"???????????????????????????????????????? (1)
??? table="table_name"????????????????????????????????????????? (2)
??? lazy="true|false"?????????????????????????????????????????? (3)
??? inverse="true|false"??????????????????????????????????????? (4)
??? cascade="all|none|save-update|delete|all-delete-orphan"???? (5)
??? sort="unsorted|natural|comparatorClass"???????????????????? (6)
??? order-by="column_name asc|desc"???????????????????????????? (7)
??? where="arbitrary sql where condition"?????????????????????? (8)
??? outer-join="true|false|auto"??????? ????????????????????????(9)
>?
(1) name 集合屬性的名稱
(2) table (可選)目標(biāo)關(guān)聯(lián)數(shù)據(jù)庫表
(3) lazy (可選——默認(rèn)為false)允許延遲加載(lazy initialization )
(4) inverse (可選——默認(rèn)為false) 標(biāo)記這個(gè)集合作為雙向關(guān)聯(lián)關(guān)系中的方向一端。
(5) cascade (可選——默認(rèn)為none) 讓操作級聯(lián)到子實(shí)體
(6) sort(可選-默認(rèn)為unsorted)指定集合的排序順序, 其可以為自然的(natural)或者給定一個(gè)用來比較的類。
(7) order-by (可選, 僅用于jdk1.4) 指定表的字段(一個(gè)或幾個(gè))再加上asc或者desc(可選), 定義Map,Set和Bag的迭代順序
(8) where (可選) 指定任意的SQL where條件。該條件將在重新載入或者刪除這個(gè)集合時(shí)使用(當(dāng)集合中的數(shù)據(jù)僅僅是所有可用數(shù)據(jù)的一個(gè)子集時(shí)這個(gè)條件非常有用)
(9) outer-join(可選-默認(rèn)為auto)是否使用外聯(lián)接
八、多對多
<many-to-many
??????? column="column_name"?????????????????????????????? (1)
??????? class="ClassName"????????????????????????????????? (2)
??????? outer-join="true|false|auto"?????????????????????? (3)
/>
(1) column(必需): 中間映射表中,關(guān)聯(lián)目標(biāo)表的關(guān)聯(lián)字段
(2) class (必需): 類名,關(guān)聯(lián)目標(biāo)類
(3) outer-join (可選 - 默認(rèn)為auto): 在Hibernate系統(tǒng)參數(shù)中hibernate.use_outer_join被打開的情況下,該參數(shù)用來允許使用outer join來載入此集合的數(shù)據(jù)。
持久化對象的狀態(tài)
¨? 瞬時(shí)(Transient)對象:使用new 操作符初始化的對象不是立刻就持久的。它們的狀態(tài)是瞬時(shí)的,也就是說它們沒有任何跟數(shù)據(jù)庫表相關(guān)聯(lián)的行為,只要應(yīng)用不再引用這些對象(不再被任何其它對象所引用),它們的狀態(tài)將會(huì)丟失,并由垃圾回收機(jī)制回收。
¨? 持久化(Persist)對象:持久實(shí)例是任何具有數(shù)據(jù)庫標(biāo)識(shí)的實(shí)例。它有持久化管理器Session統(tǒng)一管理,持久實(shí)例是在事務(wù)中進(jìn)行操作的——它們的狀態(tài)在事務(wù)結(jié)束時(shí)同數(shù)據(jù)庫進(jìn)行同步。當(dāng)事務(wù)提交時(shí),通過執(zhí)行SQL的INSERT、UPDATE和DELETE語句把內(nèi)存中的狀態(tài)同步到數(shù)據(jù)庫中。
¨? 離線(Detached)對象:Session關(guān)閉之后,持久化對象就變?yōu)殡x線對象。離線表示這個(gè)對象不能再與數(shù)據(jù)庫保持同步,它們不再受Hibernate管理。
Save() saveorupdate() update()
Automatic dirty object checking
?
Hibernate查詢
數(shù)據(jù)查詢與檢索是Hibernate中的一個(gè)亮點(diǎn)。相對其他ORM實(shí)現(xiàn)而言,Hibernate
提供了靈活多樣的查詢機(jī)制。
Hibernate Query Language (HQL)
HQL是完全面向?qū)ο蟮牟樵冋Z句,具備繼承、多態(tài)和關(guān)聯(lián)等特性。HQL(Hibernate Query Language)提供了非常強(qiáng)大的查詢功能,在官方開發(fā)手冊中,也將HQL作為推薦的查詢模式。
HQL 子句本身大小寫無關(guān),但是其中出現(xiàn)的類名和屬性名必須注意大小寫區(qū)分
Criteria Queries
Criteria Query(標(biāo)準(zhǔn)化對象查詢)通過面向?qū)ο蠡脑O(shè)計(jì),將數(shù)據(jù)查詢條件封裝為一個(gè)對象。簡單來講,Criteria Query可以看作是傳統(tǒng)SQL的對象化表示。
優(yōu)點(diǎn):可讀性好,符合Java 程序員的編碼習(xí)慣。缺點(diǎn):不夠成熟,不支持投影(projection)或統(tǒng)計(jì)函數(shù)(aggregation)。
這種方式的特點(diǎn)是比較符合Java 程序員的編碼習(xí)慣,并且具備清晰的可讀性。正因?yàn)榇?#xff0c;不少ORM實(shí)現(xiàn)中都提供了類似的實(shí)現(xiàn)機(jī)制(如Apache OJB)。
Native SQL Queries
原生SQL查詢:直接使用數(shù)據(jù)庫提供的SQL進(jìn)行查詢。
安裝配置
下載最新發(fā)布的Hibernate代碼包,拷貝需要的.jar文件。
Hibernate配置有兩中方法:
一、XML格式的配置文件,文件名默認(rèn)為“hibernate.cfg.xml“。
二、傳統(tǒng)的properties文件配置方式,文件名為“hibernate.properties”。
第一種方式,提供了易讀的結(jié)構(gòu),和更強(qiáng)的配置能力,可以直接對映射文件加以配置,使用起來更方便。第二種方式比較簡單。
User例子
實(shí)體類:必需有一個(gè)默認(rèn)的構(gòu)造函數(shù),equal() HashCode() Serializable
Session.flush()方法強(qiáng)制數(shù)據(jù)庫同步,這里即強(qiáng)制Hibernate將user實(shí)例立即同步到數(shù)據(jù)庫中。如果在事務(wù)中則不需要flush方法,在事務(wù)提交的時(shí)候,hibernate自動(dòng)會(huì)執(zhí)行flush方法,另外當(dāng)Session關(guān)閉時(shí),也會(huì)自動(dòng)執(zhí)行flush方法。
session.close()
session.flush():刷新,迫使Session執(zhí)行一些必需的SQL語句,把內(nèi)存中的對象和JDBC連接中的狀態(tài)進(jìn)行同步更新。
session.clear():要把所有的對象從session緩存中完全清除
在sessionFactory.openSession()中,hibernate會(huì)初始化
數(shù)據(jù)庫連接,與此同時(shí),將其AutoCommit 設(shè)為關(guān)閉狀態(tài)(false)。而其后,在
Session.beginTransaction 方法中,Hibernate 會(huì)再次確認(rèn)Connection 的
AutoCommit 屬性被設(shè)為關(guān)閉狀態(tài)( 為了防止用戶代碼對session 的
Connection.AutoCommit屬性進(jìn)行修改)。
Set和List的區(qū)別:
Query.list();
Query.iterate();
對于list方法而言,實(shí)際上Hibernate是通過一條Select SQL獲取所有的記錄。
并將其讀出,填入到POJO中返回。
而iterate 方法,則是首先通過一條Select SQL 獲取所有符合查詢條件的記錄的
id,再對這個(gè)id 集合進(jìn)行循環(huán)操作,通過單獨(dú)的Select SQL 取出每個(gè)id 所對應(yīng)的記
錄,之后填入POJO中返回。
也就是說,對于list 操作,需要一條SQL 完成。而對于iterate 操作,需要n+1
條SQL。
看上去iterate方法似乎有些多余,但在不同的情況下確依然有其獨(dú)特的功效,如對
海量數(shù)據(jù)的查詢,如果用list方法將結(jié)果集一次取出,內(nèi)存的開銷可能無法承受。
另一方面,對于我們現(xiàn)在的Cache機(jī)制而言,list方法將不會(huì)從Cache中讀取數(shù)據(jù),
它總是一次性從數(shù)據(jù)庫中直接讀出所有符合條件的記錄。而iterate 方法因?yàn)槊看胃鶕?jù)
id獲取數(shù)據(jù),這樣的實(shí)現(xiàn)機(jī)制也就為從Cache讀取數(shù)據(jù)提供了可能,hibernate首先會(huì)
根據(jù)這個(gè)id 在本地Cache 內(nèi)尋找對應(yīng)的數(shù)據(jù),如果沒找到,再去數(shù)據(jù)庫中檢索。如果系
統(tǒng)設(shè)計(jì)中對Cache比較倚重,則請注意編碼中這兩種不同方法的應(yīng)用組合,有針對性的改
善代碼,最大程度提升系統(tǒng)的整體性能表現(xiàn)。
Hibernate3發(fā)布beta版本 支持EJB3風(fēng)格對象持久化
(2004.12.21)?? 來自:CSDN?? 熊節(jié)?
昨天(12月20日)Hibernate框架發(fā)布了3.0版本的第一個(gè)beta版本。據(jù)作者Gavin King表示,Hibernate 3.0將于明年(2005年)第一季度正式發(fā)布。Hibernate是一個(gè)基于POJO(Plain-Old Java Object,普通Java對象)的O/R mapping框架,也是目前J2EE社群最流行的對象持久化工具。正在制訂中的EJB3規(guī)范就大量借鑒了Hibernate的經(jīng)驗(yàn)。
在beta1版本中,Hibernate3并未提供對J2SE 5.0的支持,這主要是因?yàn)槌鲇诩嫒菪缘目紤]。Gavin King表示,將在2005年逐步引入J2SE 5.0提供的新語言特性,例如泛型、元數(shù)據(jù)標(biāo)注等。
Hibernate3主要的新特性包括:
實(shí)現(xiàn)了EJB3風(fēng)格的持久化操作。在原有的saveOrUpdate()和saveOrUpdateCopy()兩個(gè)方法之外,又提供了EJB3風(fēng)格的create()和merge()兩個(gè)操作。
提供更強(qiáng)的映射靈活性。允許將一個(gè)類映射到多張表,允許混合使用“每個(gè)繼承體系一張表”和“每個(gè)子類一張表”的映射策略,等等。
支持存儲(chǔ)過程和手寫SQL,并且可以用手寫SQL替代Hibernate自動(dòng)生成的SQL語句。
基于AST(抽象語法樹)的HQL解析。
字段級的懶加載。每個(gè)屬性都可以在映射描述符中聲明“l(fā)azy=true”,這樣聲明的屬性會(huì)到真正使用時(shí)才從數(shù)據(jù)庫加載。不過,實(shí)現(xiàn)這項(xiàng)功能需要首先在編譯期對字節(jié)碼進(jìn)行增強(qiáng)。
Hibernate最佳實(shí)踐(Best Practices)
1、? 使用Configuration裝載映射文件時(shí),不要使用絕對路徑裝載。最好的方式是通過getResourceAsStream()裝載映射文件,這樣Hibernate會(huì)從classpath中尋找已配置的映射文件。
2、? SessionFactory的創(chuàng)建非常消耗資源,整個(gè)應(yīng)用一般只要一個(gè)SessionFactory就夠了,只有多個(gè)數(shù)據(jù)庫的時(shí)候才會(huì)使用多個(gè)SessionFactory。
3、? 在整個(gè)應(yīng)用中,Session和事務(wù)應(yīng)該能夠統(tǒng)一管理。(Spring為Hibernate提供了非常好的支持)
4、? 將所有的集合屬性配置設(shè)置為懶加載(lazy=”true”)。在hibernate2.x版本中,lazy默認(rèn)值是“false”,但hibernate3.x已經(jīng)將lazy的默認(rèn)改為“true”了。
5、? 在定義關(guān)聯(lián)關(guān)系時(shí),集合首選Set,如果集合中的實(shí)體存在重復(fù),則選擇List(在定義配置文件時(shí),可以將List定義為bag),數(shù)組的性能最差。
6、? HQL子句本身大小寫無關(guān),但是其中出現(xiàn)的類名和屬性名必須注意大小寫區(qū)分。
7、? 在一對多的雙向關(guān)聯(lián)中,一般將集合的inverse屬性設(shè)為true,讓集合的對方維護(hù)關(guān)聯(lián)關(guān)系。例如:Group-User,由User來維護(hù)Group和User的關(guān)聯(lián)關(guān)系。
8、? 在非分布式架構(gòu)中,不需要使用DTO來向上層傳輸數(shù)據(jù)。直接使用POJO的Entity就可以了。
在<many-to-one>中,將outer-join 設(shè)置為false。If the SQL statements use join operations that are too complex and
slow, set outer-join to false for <many-to-one> associations (this is
enabled by default). Also try to tune with the global hibernate.
max_fetch_depth configuration option, but keep in mind that this
is best left at a value between 1 and 4.
9、? 如果要精通Hibernate,熟練掌握關(guān)系數(shù)據(jù)庫理論和SQL是前提。
10、????????????? ?
If the SQL statements use join operations that are too complex and
slow, set outer-join to false for <many-to-one> associations (this is
enabled by default). Also try to tune with the global hibernate.
max_fetch_depth configuration option, but keep in mind that this
is best left at a value between 1 and 4.
總結(jié)
以上是生活随笔為你收集整理的Hibernate第一次课(2)---Hibernate原理简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。