Hibernate介紹
出現(xiàn)背景
在Hibernate等ORM框架出現(xiàn)之前凉倚,Java Web應(yīng)用通常使用JDBC來(lái)進(jìn)行持久層的數(shù)據(jù)庫(kù)訪問(wèn)等操作兼都,但是JDBC存在著很多缺點(diǎn),比如實(shí)現(xiàn)業(yè)務(wù)邏輯的代碼和數(shù)據(jù)庫(kù)訪問(wèn)的代碼摻雜在一起稽寒,使程序結(jié)構(gòu)不清晰扮碧,可讀性差;在程序代碼中嵌入面向關(guān)系的SQL語(yǔ)句瓦胎,使開(kāi)發(fā)人員不能完全運(yùn)用面向?qū)ο蟮乃季S來(lái)編寫(xiě)程序芬萍;業(yè)務(wù)邏輯和關(guān)系數(shù)據(jù)模型綁定尤揣,如果關(guān)系模型發(fā)生變化,需要手工修改程序代碼中所有相關(guān)的SQL語(yǔ)句柬祠,增加了程序維護(hù)的難度等等北戏。
如何解決問(wèn)題
為了解決直接使用JDBC的諸多弊端,以Hibernate為代表的ORM框架應(yīng)運(yùn)而生漫蛔。Hibernate是一個(gè)基于Java的開(kāi)源的持久化中間件嗜愈,對(duì)JDBC做了輕量的封裝。它采用ORM映射機(jī)制莽龟,負(fù)責(zé)實(shí)現(xiàn)Java對(duì)象和關(guān)系數(shù)據(jù)庫(kù)之間的映射蠕嫁,把SQL語(yǔ)句傳給數(shù)據(jù)庫(kù),并且把數(shù)據(jù)庫(kù)返回的結(jié)果封裝成對(duì)象毯盈。Hibernate內(nèi)部封裝了JDBC訪問(wèn)數(shù)據(jù)庫(kù)的操作剃毒,向上層應(yīng)用提供了面向?qū)ο蟮臄?shù)據(jù)庫(kù)訪問(wèn)API,使得Java程序員可以輕松使用面向?qū)ο蟮木幊趟季S去操縱數(shù)據(jù)庫(kù)搂赋,從 95% 的公共數(shù)據(jù)持續(xù)性編程工作中解放出來(lái)赘阀。
Why Hibernate
同樣比較流行的ORM還有MyBatis等,Hibernate相比這些框架有以下優(yōu)勢(shì)脑奠,因此也是我們選擇它作為持久層框架的原因基公,至于Hibernate和MyBatis的詳細(xì)對(duì)比以及MyBatis的優(yōu)勢(shì)可以見(jiàn)這篇文章:數(shù)據(jù)庫(kù)持久層框架iBatis、myBatis宋欺、Hibernate對(duì)比轰豆。
- Hibernate的DAO層開(kāi)發(fā)比MyBatis簡(jiǎn)單,Mybatis需要維護(hù)SQL和結(jié)果映射齿诞。
- Hibernate對(duì)對(duì)象的維護(hù)和緩存要比MyBatis好酸休,對(duì)增刪改查的對(duì)象的維護(hù)要方便。
- Hibernate數(shù)據(jù)庫(kù)移植性很好掌挚,MyBatis的數(shù)據(jù)庫(kù)移植性不好雨席,不同的數(shù)據(jù)庫(kù)需要寫(xiě)不同的SQL。
- Hibernate有更好的二級(jí)緩存機(jī)制吠式,可以使用第三方緩存。MyBatis本身提供的緩存機(jī)制不佳抽米。
Hibernate與Spring的整合開(kāi)發(fā)
了解完Hibernate后特占,我將通過(guò)在電影售票系統(tǒng)大作業(yè)中整合Hibernate來(lái)介紹該框架的基本配置與使用,主要的開(kāi)發(fā)環(huán)境為:Intellij IDEA + SpringMVC + Spring +Hibernate + MySQL
數(shù)據(jù)庫(kù)準(zhǔn)備
我們小組使用了MySQL數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù)云茸,并通過(guò)MySQL Workbench這一GUI界面對(duì)數(shù)據(jù)庫(kù)進(jìn)行管理是目。
在開(kāi)始應(yīng)用開(kāi)發(fā)之前,我們先設(shè)計(jì)了基本的數(shù)據(jù)庫(kù)表和相應(yīng)字段标捺,并在表之間設(shè)置外鍵關(guān)聯(lián)關(guān)系懊纳。
在IDEA中引入Hibernate
使用Maven創(chuàng)建項(xiàng)目揉抵,在Project Structure的Modules中添加Hibernate模塊并指定配置文件為hibernate.cfg.xml,Maven會(huì)自動(dòng)幫助我們下載相應(yīng)的依賴(lài)包嗤疯。
編寫(xiě)Hibernate配置文件
引入Hibernate后冤今,IDE在META-INF目錄下為我們自動(dòng)創(chuàng)建了一個(gè)Hibernate的配置文件,我們可以在其中配置數(shù)據(jù)庫(kù)及緩存相關(guān)的屬性茂缚,比如設(shè)置事務(wù)的自動(dòng)提交屬性為true戏罢,可以簡(jiǎn)化業(yè)務(wù)層的代碼編寫(xiě)。
除了上述的配置文件脚囊,我們還需要其他的配置文件將Spring與Hibernate整合起來(lái)龟糕,這里我創(chuàng)建了infrastructure.xml。
可以看到悔耘,在該xml配置文件中讲岁,我們使用了c3p0數(shù)據(jù)源,c3p0是一個(gè)開(kāi)源的JDBC連接池衬以,它實(shí)現(xiàn)了數(shù)據(jù)源和JNDI綁定缓艳,支持JDBC3規(guī)范和JDBC2的標(biāo)準(zhǔn)擴(kuò)展。同時(shí)我們指定了Spring進(jìn)行組件掃描的基礎(chǔ)包泄鹏,用來(lái)掃描所有Entity注解進(jìn)而實(shí)現(xiàn)Spring的自動(dòng)裝配郎任。再結(jié)合上節(jié)提到的hibernate.cfg.xml,我們就定義好了Hibernate所需要的session工廠bean备籽,通過(guò)session工廠就可以獲取session并調(diào)用Hibernate內(nèi)置的CRUD方法舶治。
在該配置文件的最上方還引用了hibernate.properties,該配置文件定義了數(shù)據(jù)庫(kù)連接的各種屬性车猬,比如url霉猛、用戶名和密碼等供infrastructure.xml引用,可以避免硬編碼屬性珠闰。
將數(shù)據(jù)庫(kù)表映射成Java實(shí)體類(lèi)
編寫(xiě)完Hibernate所需的配置文件后惜浅,就可以成功連接到MySQL數(shù)據(jù)庫(kù)。下一步操作就是編寫(xiě)與數(shù)據(jù)庫(kù)表相對(duì)應(yīng)的實(shí)體類(lèi)(持久化類(lèi))伏嗜,而IDEA強(qiáng)大的一點(diǎn)在于坛悉,它可以直接將數(shù)據(jù)庫(kù)表映射成Java實(shí)體類(lèi)并加上基本的注解,從而節(jié)省大量的時(shí)間承绸。
設(shè)置Hibernate關(guān)聯(lián)映射
數(shù)據(jù)庫(kù)中表與表之間會(huì)存在不同的主外鍵關(guān)聯(lián)關(guān)系肌割,而Hibernate作為ORM框架踪蹬,自然需要將表之間的關(guān)系映射成實(shí)體類(lèi)之間的關(guān)聯(lián)映射關(guān)系。Hibernate為我們提供了@OneToMany、@ManyToOne愤炸、@ManyToMany等多種注解來(lái)表示實(shí)體類(lèi)間的關(guān)聯(lián)關(guān)系。
以上圖中用戶和評(píng)論之間的雙向一對(duì)多關(guān)聯(lián)為例,多端作為關(guān)聯(lián)關(guān)系的主控端,涉及到兩個(gè)實(shí)體的增刪改查操作都應(yīng)由多端完成晤锹,這樣可以減少SQL語(yǔ)句的執(zhí)行,提高數(shù)據(jù)訪問(wèn)性能彤委。一端作為關(guān)聯(lián)關(guān)系的被控端鞭铆,這種被控使用mappedBy屬性來(lái)表明,同時(shí)一端設(shè)置了cascade級(jí)聯(lián)屬性表明在對(duì)用戶進(jìn)行刪除和保存等操作時(shí)葫慎,該操作也會(huì)級(jí)聯(lián)到關(guān)聯(lián)到該用戶的所有評(píng)論實(shí)體衔彻,從而保證業(yè)務(wù)邏輯上的正確性,并且省去了手動(dòng)保存評(píng)論的麻煩偷办。
而在上圖的評(píng)論實(shí)體中艰额,我們可以相對(duì)應(yīng)地看到針對(duì)User的@ManyToOne注解,而@JoinColumn注解指定了comment表中使用user_id作為外鍵關(guān)聯(lián)到user表的user_id屬性椒涯,從而在關(guān)系層次上建立起了兩個(gè)表之間的聯(lián)系柄沮。
編寫(xiě)B(tài)aseDAO
設(shè)置完實(shí)體類(lèi)之間的關(guān)聯(lián)映射后,就可以進(jìn)入Hibernate的業(yè)務(wù)代碼編寫(xiě)階段废岂。根據(jù)MVC的分層架構(gòu)祖搓,我們將整個(gè)應(yīng)用分為顯示層(View),控制層(Controller)湖苞,業(yè)務(wù)邏輯層(Service)和數(shù)據(jù)訪問(wèn)層(DAO)
其中Controller層負(fù)責(zé)處理請(qǐng)求的路由拯欧,并調(diào)用Service層的業(yè)務(wù)邏輯方法執(zhí)行業(yè)務(wù),而Service層需要調(diào)用DAO層的數(shù)據(jù)訪問(wèn)方法來(lái)實(shí)現(xiàn)與底層數(shù)據(jù)庫(kù)的交互财骨,每一層之間都面向接口編程镐作,保持了較松的耦合性,同時(shí)架構(gòu)清晰隆箩,增強(qiáng)了項(xiàng)目的可維護(hù)性和可伸縮性该贾。
在實(shí)際編程時(shí),我們通常都是自底向上從DAO層開(kāi)始編寫(xiě)代碼捌臊。DAO層封裝了與底層數(shù)據(jù)庫(kù)交互的方法杨蛋,而有一些通用的CRUD方法是每一個(gè)實(shí)體類(lèi)都需要的,因此這些方法可以被封裝成一個(gè)基礎(chǔ)的BaseDAO泛型接口理澎,每一個(gè)實(shí)體類(lèi)各自的DAO接口只需要繼承BaseDAO接口的實(shí)現(xiàn)即可根據(jù)業(yè)務(wù)需求繼續(xù)擴(kuò)展逞力,這也體現(xiàn)了代碼復(fù)用的思想。
從上圖接口中可以發(fā)現(xiàn)BaseDAO定義了很多不同的查詢(xún)方法糠爬,這也就引出了Hibernate另一方面的重要知識(shí)掏击,即HQL查詢(xún)和標(biāo)準(zhǔn)查詢(xún)。
HQL查詢(xún)
Hibernate 查詢(xún)語(yǔ)言(HQL)是一種面向?qū)ο蟮牟樵?xún)語(yǔ)言秩铆,類(lèi)似于 SQL,但不是去對(duì)表和列進(jìn)行操作,而是面向?qū)ο蠛退鼈兊膶傩浴?HQL 查詢(xún)被 Hibernate 翻譯為傳統(tǒng)的 SQL 查詢(xún)從而對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作殴玛。
盡管能直接使用本地 SQL 語(yǔ)句捅膘,但是應(yīng)該盡可能的使用 HQL 語(yǔ)句,以避免數(shù)據(jù)庫(kù)關(guān)于可移植性的麻煩滚粟,并且體現(xiàn)了 Hibernate 的 SQL 生成和緩存策略寻仗。
在 HQL 中一些關(guān)鍵字比如 SELECT ,F(xiàn)ROM 和 WHERE 等凡壤,是不區(qū)分大小寫(xiě)的署尤,但是一些屬性比如表名和列名是區(qū)分大小寫(xiě)的。
以FROM語(yǔ)句為例展示一下HQL的語(yǔ)法亚侠。
如果想要在存儲(chǔ)中加載一個(gè)完整并持久的對(duì)象曹体,可以使用 FROM 語(yǔ)句。
String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();
在BaseDAO中我編寫(xiě)了一些工具方法來(lái)簡(jiǎn)化HQL查詢(xún)代碼的編寫(xiě)硝烂。
標(biāo)準(zhǔn)查詢(xún)
Hibernate 提供了操縱對(duì)象和相應(yīng)的 RDBMS 表中可用的數(shù)據(jù)的替代方法箕别。一種方法是標(biāo)準(zhǔn)的 API,它允許開(kāi)發(fā)者建立一個(gè)標(biāo)準(zhǔn)的可編程查詢(xún)對(duì)象來(lái)應(yīng)用過(guò)濾規(guī)則和邏輯條件滞谢。
Hibernate Session 接口提供了 createCriteria() 方法串稀,可用于創(chuàng)建一個(gè) Criteria 對(duì)象,使應(yīng)用程序執(zhí)行一個(gè)標(biāo)準(zhǔn)查詢(xún)時(shí)返回一個(gè)持久化對(duì)象的類(lèi)的實(shí)例狮杨。
以下是一個(gè)最簡(jiǎn)單的標(biāo)準(zhǔn)查詢(xún)的例子母截,它只是簡(jiǎn)單地返回對(duì)應(yīng)于員工類(lèi)的每個(gè)對(duì)象:
Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();
同時(shí)可以使用 Criteria 對(duì)象可用的 add() 方法去添加一個(gè)標(biāo)準(zhǔn)查詢(xún)的限制,限制包括等于(eq)橄教、大于(gt)清寇、小于(lt)等等邏輯謂詞,我也在BaseDAO中將其寫(xiě)成了工具方法颤陶,即根據(jù)條件類(lèi)型來(lái)構(gòu)建Criterion颗管。
同時(shí)我也添加了上述使用到的ConditionType和Condition等輔助類(lèi)來(lái)簡(jiǎn)化標(biāo)準(zhǔn)查詢(xún)的代碼。
利用這些工具類(lèi)和工具方法滓走,可以大大簡(jiǎn)化標(biāo)準(zhǔn)查詢(xún)的代碼垦江,如下所示:
/**
* 根據(jù)Criterion列表獲取集合對(duì)象
*
* @param criterions
* @return
*/
@Override
public List<T> find(Criterion... criterions) {
return createCriteria(getCurrentSession(), getEntityClass(), criterions).list();
}
介紹完BaseDAO中的主要方法后,大作業(yè)數(shù)據(jù)訪問(wèn)層的基礎(chǔ)功能就已經(jīng)搭建好了搅方,之后只需根據(jù)業(yè)務(wù)需求擴(kuò)展BaseDAO比吭,進(jìn)而構(gòu)建Service層和Controller層以完成業(yè)務(wù)邏輯的處理,這些內(nèi)容就不再贅述姨涡。
至此Hibernate就成功和Spring進(jìn)行了整合衩藤,并展示了它的強(qiáng)大功能。
參考
Hibernate 教程
Hibernate之條件查詢(xún)(Criteria Queries)
用hibernate+注解實(shí)現(xiàn)各種關(guān)系映射
數(shù)據(jù)庫(kù)持久層框架iBatis涛漂、myBatis赏表、Hibernate對(duì)比
SSH——hibernate 利用注解實(shí)現(xiàn)實(shí)體關(guān)聯(lián)映射詳解
Spring-SpringMVC-Hibernate在IntelliJ與Maven的環(huán)境下搭建
Spring框架教程