第227期 / September 5, 2016

研發新視界

分享到臉書!分享到維特!分享到噗浪!分享到Google+!分享到微博!轉寄友人友善列印

使用Hibernate操作資料庫介紹

作者/黃瀚明

[發表日期:2016/9/5]

前言

Hibernate是非常知名的ORM (Object Relational Mapping)解決方案,能讓程式開發者以非常輕鬆的方式操作資料庫,也可達到程式與資料庫的低耦合。以往我們在程式碼裡面寫SQL語法,但各家資料庫的SQL語法不盡相同,要從Mysql轉換到MS Sql,還要一一檢查程式碼內的SQL是否都適用。使用Hibernate,我們只要修改hibernate的設定檔就可以快速轉換資料庫。廢話不多說,我們馬上開始Hibernate的初體驗。

開始使用Hibernate

要開始使用Hibernate,第一步當然是先把DB Schema建起來。 (Hibernate也可以幫你建Table,透過你撰寫的設定檔來解析Table欄位,然後自動建立Table,不過我們這裡還是一步一步慢慢來) ,請在資料庫建立以下表格:


《圖一》


這個表格裡面有三個欄位,Employee_id是會自動增加的primary key,Name是該員工的名字,on_board則是該員工的到職日,用timestamp儲存。

建立好表格後,我們需要告訴Hibernate如何連接資料庫,包含資料庫的位置(IP)、帳號、密碼等資訊。另外,除了連接資料庫的資訊外,還須要讓Hibernate知道表格與物件的對應關係。以上所說的資訊都必須在hibernate.cfg.xml定義清楚,Hibernate會到這個檔案解析所需資訊。

聽到撰寫設定檔可能會讓你卻步,想直接關掉瀏覽器,回去用JDBC算了!不過先等等,如果你的IDE是NetBeans的話,倒是有一個快速生成設定檔的方法。如圖,在專案上面按右鍵、New、Other


《圖二》


在過濾欄位輸入Hibernate,於右側File Types選擇Hibernate Configuration Wizard。


《圖三》


預設檔名是hibernate.cfg,名字當然可以改變,不過這邊建議還是用預設的名字會比較好。


《圖四》


選擇資料庫的連線方式。如果沒有看到想要的連線方式,可以自己新增一筆。我們這裡使用的是Mysql,所以Database Dialect會是org.hibernate.dialect.MySQLDialect。用這種wizard的好處是除了比較方便,遇到像這種一長串的參數也比較不會打錯字。


《圖五》


按下Finish後就會自動產生hibernate.cfg.xml。NetBeans有幾種方式可以檢視、編輯這種xml檔,hibernate.cfg.xml產生出來後,顯示的是Design模式,NetBeans幫你把xml做成可互動的GUI介面了。


《圖六》


當然也可以切到Source模式,自己手動編輯xml檔的內容。


《圖七》


設定檔裡面可以看到driver_class是com.mysql.jdbc.Driver,所以記得要到MySQL官網下載JDBC的Driver,並import到專案裡面來。

前面提到,hibernate.cfg.xml裡面除了連接資料庫的資訊外,還須要讓Hibernate知道表格與物件的對應關係,當然你還可以額外設定其他參數。很遺憾的前面這個Wizard沒辦法幫你寫這段設定,不過還好這段還算簡單。


《圖八》


除了原本的property以外,我們新增了connection.pool_size及show_sql屬性。

Connection.pool_size是Hibernate的預設connection-pool設定,這邊使用Hibernate內建的connection-pool。要注意的是,雖然Hibernate已經有內建connection-pool,但是Hibernate官方網站並不建議在產品中使用內建的connection-pool,因為內建的connection-pool功能並不是那麼齊全。如果要使用connection-pool的話,可以考慮使用c3p0 connection-pool。(參下圖,實際執行程式碼時會在Log裡看到not for production use!的警語)


《圖九》


show_sql顧名思義就是會在Hibernate執行的時候把實際操作資料庫時的SQL語法顯示出來,方便我們除錯。

我們在標籤內新增了mapping標籤,Mapping標籤是在告訴Hibernate要到com.syscom.hbm.Employee.hbm.xml去解析表格與物件的對應關係。因此我們要提供這個xml檔,不過既然這個xml檔是紀錄表格與物件的對應關係,那麼我們就先來撰寫Hibernate用來存放資訊的物件。


《圖十》


Employee物件,對應到表格的三個欄位,分別有employId、name及onBoard三個屬性。物件這邊的寫法相對簡單,只要有對應表格的屬性即可。

(沒錯,不一定要有getter和setter也可以)要注意的是必須要有無參數的建構子,這個建構子是給Hibernate使用的,Hibernate會利用JAVA的反射機制(Reflection)為你建立這個物件的實例,所以無參數建構子一定要明確寫出來。至於其他建構子,就只是讓你在寫程式時呼叫用的。

有了物件,就可以開始撰寫前面提到的com.syscom.hbm.Employee.hbm.xml。首先,我們先新增com.syscom.hbm這個package


《圖十一》


在package上面按右鍵,一樣可以找到Hibernate Mapping Wizard,讓NetBeans帶領你一步一步設定。


《圖十二》


使用Hibernate Mapping Wizard可以很輕易地找到要Mapping的物件,按下Class to Map後面的按鈕來搜尋我們剛才建立的Employee.java。


《圖十三》



《圖十四》


Hibernate Mapping Wizard會利用我們前面設定的hibernate.cfg.xml裡面的參數到資料庫裡面撈取現有表格,因此當你開啟Hibernate Mapping Wizard,同時也可以驗證前面連接資料庫的參數是否有誤。

按下完成後,我們就可以在產生出來的Employee.hbm.xml裡面加入property了。


《圖十五》


Id標籤定義了這個表格內的主鍵,name參數對應到物件內的屬性名稱,而column參數對應的是表格欄位的名稱。Generator標籤裡的class=”increment”則說明了若沒有指定的話,這個主鍵會自動依資料庫現有的資料遞增。

Property標籤的參數基本上和id標籤內的參數差不多。不過您可能已經發現,我們在name這個屬性並沒有加上column這個參數,這是因為當沒有指定column參數時,Hibernate能夠自己決定該屬性對應的表格欄位。沒有指定column參數時,Hibernate會使用該屬性的名稱作為表格欄位。另外,onBoard屬性中指定了type參數,而name屬性卻沒有指定,當我們不指定type時,Hibernate會自動使用JAVA的反射機制(Reflection)來決定該欄位應該對應的型別。

必須注意的是,雖然Hibernate能夠自己決定屬性的型別,但是由於Hibernate是透過JAVA的反射機制來決定屬性型別,這個決定屬性型別的過程還是會增加一些額外的處理負擔。因此最好還是直接在xml檔裡直接寫明屬性的型別。

至此,前置作業算是完成了,我們可以開始實際撰寫JAVA程式來使用Hibernate。

我們新增了一個Class,並在裡面新增了init與close兩個Function。這兩個Function非常簡單,就只是負責SessionFactory的建立與關閉而已。後面使用sessionFactory前,要確定有先呼叫init這個方法;程式結束時也要記得呼叫close()方法。


《圖十六》


要建立SessionFactory只要用程式中第26行來建立即可。此時程式會到ClassPath路徑下找尋我們前面建立的hibernate.cfg.xml來建立SessionFactory。當然,如果你前面建立hibernate.cfg.xml時改了名字和路徑,這行就要改一下。例如你改成了myconfig.cfg.xml,並放在com.syscom.hbm這個package底下,就要這樣改寫:


《圖十七》


使用Hibernate操作資料庫非常簡單,我們先來看看怎麼新增資料到資料庫:


《圖十八》


如上圖所示,要新增一筆資料,只要建立一個Employee的物件,把資料塞進該物件,再利用session.save就可以直接存到資料庫裡面了。至於Employee表格的主鍵,由於我們在hibernate.cfg.xml內已經指定讓他自動增加,因此就算不指定值也是沒關係的。(程式碼中把資源放到try後面的括弧內,這是使用了JAVA的try-resource語法,這個語法會在try區塊結束後自動關閉資源,以免開發者忘記關閉資源。JAVA從JDK7開始支援Try-resource語法,使用前請先注意自己的JAVA版本。)

執行後到資料庫裡查看是否正確存入資料:


《圖十九》


資料庫有了資料,我們就可以試著到資料庫裡撈資料出來看看。


《圖二十》


要到資料庫撈資料,只需要使用session.createQuery()這個function就可以。我們在這個function的參數帶入了”Select e from Employee as e”這個字串,這個字串看起來像是SQL,但實際上是Hibernate專用的查詢語言-HQL (Hibernate Query Language)。HQL的寫法與SQL大同小異,要注意的是SQL是使用表格的欄位名來操作,而HQL則是用Hibernate物件的屬性名來操作。

另外,你可能也會看到有人直接寫”from Employee”,直接寫”from Employee”基本上和”Select e from Employee as e”是一樣的,Hibernate會在背後把”from Employee”轉換成”Select e from Employee as e”。

我們來看看上面程式碼的結果:


《圖二十一》


在印出我們從資料庫撈出來的資訊之前,Hibernate先寫了一行SQL。這是因為我們在hibernate.cfg.xml裡指定了show_sql=true。若把show_sql=true拿掉或是改為false,這行SQL就不會再出現。從程式碼中看到,我們從資料庫拿出來的資訊,直接就被Hibernate轉換成了物件,要存取這些資訊,透過物件的getter/setter就可以很輕鬆的拿到我們要的資訊。

前面程式碼展示的是最簡單的Select e from Employee as e,我們來試著加上Where條件:


《圖二十二》


Where條件中的條件值,必須使用setParameter來給定。給定的方式有兩種,一種是使用參數的位置,如程式碼第46~47行。HQL裡面的條件值用問號代替,然後再用setParameter指定條件值,例如第47行指的是”第0個條件的數值是Jorge”。

另一種方式是直接指定條件值名稱對應的數值。使用這種方法,必須在HQL裡面定義好條件值的名稱,例如第48行的 where e.name=:name。後面使用setParameter時就要帶條件值名稱,而非位置。

不過,由於HQL在這只是個字串,NetBeans也不會幫你檢查HQL正確與否,程式還沒執行,要怎麼知道自己寫的HQL是否正確呢?當然你可以直接執行程式,看看是否會出錯,不過如果你是使用NetBeans,我們有更聰明的方法:


《圖二十三》


在hibernate.cfg.xml上按右鍵,選擇Run HQL Query,NetBeans會帶出HQL的測試頁面,只要在這個頁面上輸入HQL,再按下執行的按鈕,就能夠馬上看到HQL的執行結果:


《圖二十四》


最後我們來看一下刪除和修改。


《圖二十五》


刪除資料前必須先從資料庫中把要刪除的資料找出來,然後再直接使用session.delete()就可以刪除資料。

修改資料一樣要先把資料庫中的資料拿出來,然後針對目標物件(資料)做修改,例如我們這裡把Name從Jorge改成了Henry。要注意的是修改資料可以不用像其他操作一樣呼叫session.xxx(),修改完物件內容後,Hibernate會在session close時或Transaction commit時去比對物件內容和資料庫內容,如果不同就會去更新資料庫,因此在操作時要格外注意。


《圖二十六》


結語

以上是Hibernate的基本操作方法,在程式碼中操作Hibernate物件時,很有可能會不小心更動到資料庫內容,所以在使用Hibernate時要特別小心。另外,雖然基本操作方法非常簡單,還是建議讀者去了解一下Hibernate物件的生命週期,會對Hibernate有更深一層的了解。

參考資料

1.http://docs.jboss.org/hibernate/orm/5.1/quickstart/html_single/

2.http://www.mchange.com/projects/c3p0/