Q.怎麼配置Hibernate?
A.Configuration類使用配置hibernate.cfg.xml(或者hibernate.properties)以及映射文件*.hbm.xml來創建(例如,配置和引導hibernate)SessionFactory,然後SessionFactory創建Session的實例。Session的實例是持久層服務對外提供的主要接口。
hibernate.cfg.xml(或者你也可以使用hibernate.properties):這兩個文件都是用來配置hibernate服務(數據庫連接的驅動類,連接URL,用戶名,密碼,方言等)。如果這兩個文件同時存在於classpath裏的話,那麼hibernate.cfg.xml會覆蓋hibernate.properties文件裏的配置。
映射文件(*.hbm.xml):這些文件都是用來對持久層對象和關係數據庫進行映射的。最好的方式是對每個對象都使用單獨的映射文件(例如一個類一個文件),因爲如果在一個文件裏存放大量的持久層對象,那麼這個文件就變得非常難管理和維護。約定的命名方式是映射文件名和持久層類名(POJO)保持一致。例如,Account.class的映射文件名爲Account.hbm.xml。或者,你也可以在類文件的代碼里加上hibernate的註解,從而不需要使用配置文件。
Q.什麼是SessionFactory?它是線程安全的嗎?
A.SessionFactory對應Hibernate的一個數據存儲的概念,並且它是線程安全的,可以被多個線程併發訪問,也可以請求session和單個數據庫的不可變編譯過的映射的緩存。SessionFactory一般只會在啓動的時候構建。對於應用代碼,最好對SessionFactory通過單例的模式進行封裝以便於訪問。
1
|
SessionFactory
sessionFactory = new Configuration(
).configure( ).buildSessionfactory( ); |
Q.Session是什麼?兩個線程能共享同一個session嗎?
A.Session是一個輕量級非線程安全的對象(線程間不能共享session),它表示與數據庫進行交互的一個工作單元。Session是被SessionFactory創建的,在任務完成之後它會被關閉。Session是持久層服務對外提供的主要接口。Session會延遲獲取數據庫連接(也就是在需要的時候纔會獲取)。爲了避免創建太多的session,可以使用ThreadLocal來取得當前的session,無論你調用多少次currentSession()方法,返回的都是同一個session。下面是示例代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class
HibernateUtil { public static
final
ThreadLocal local = new ThreadLocal(); public static
Session currentSession() throws HibernateException
{ Session
session = (Session) local.get(); //open
a new session if this thread has no session if (session
== null )
{ session
= sessionFactory.openSession(); local.set(session); } return session; } } |
有一點很重要的就是如果一個工作單元完成了,你需要關閉你的session。注意:保持你的Hibernate Session API簡單易用。比較常見的場景是,hibernate會和Spring框架一起使用,通過HibernateTemplate來整合。
Q.解釋hibernate對象的狀態?解釋hibernate對象的生命週期?
A.持久層(persistent )對象和集合都是存活時間短暫的單線程對象,它們保存持久層的狀態。這些對象的狀態會根據你的刷新規則(例如,一旦有setXXX()方法被調用了就自動刷新,或者有數據項從集合、列表等刪除時就刷新,你也可以通過session.flush()和transaction.commit()這兩個函數調用來定義你自己的同步策略)來與數據庫保持同步。如果你從一個持久層的集合(例如Set)裏刪除一項,那麼它要麼被立即從數據庫裏刪除,或者當flush()或則commit()方法被調用時刪除,具體的表現取決於你的刷新策略。它們都是普通的Java對象(POJO,Plain Old Java Object),只不過當前關聯了一個session。一旦關聯的session被關閉,持久層對象就成爲了遊離對象(detached object),這時候你就可以在隨便使用它們了,就像是用在業務層,持久層等其他應用層面的數據傳輸對象一樣。
遊離(detached )對象和集合都是和session相關聯的持久層對象的實例,只不過它們現在沒有和session進行關聯。這種對象可以被隨便使用,它不會對你的數據庫有任何影響。遊離對象後面也可以通過調用類似session.update(),session.saveOrUpdate()等方法來依附到其他的session上,然後再次成爲持久層對象。
瞬態(transient)對象和集合是從來沒有和session相關聯的持久層對象的實例。這些對象可以自由使用,並且不會對你的數據庫造成任何影響。當通過session.save(),session.persist()方法來使得瞬態對象和一個session進行關聯時,瞬態對象就成爲了持久層對象。
Q.使用遊離對象(detached object)有什麼好處呢?
優點:
- 當因用戶的思考時間而需要使用長事務時,最好的方式是把長事務分成一個或者多個事務。你可以使用來自於第一個事務的遊離對象來承載持久層的所有數據。這些遊離的對象在事務外被修改,然後可以通過另一個session來加入到新的事務裏。
缺點:
- 一般來說,使用遊離對象的方式是比較笨重的,並且如果可以的話最好不要使得session變得比較混亂。最好的方式是丟棄這些對象,然後在後面的請求裏重新獲取新的對象。這個方式不僅更具有移植性,而且更加高效——因爲這些對象會留在Hibernate的緩存裏。
- 同時,從純粹的富領域驅動的方式來看,比較推薦的方式是使用DTO(DataTransferObject)和DO(DomainObject)來保持Service層和UI層之間的分離。
Q.什麼時候對象會變成遊離的?
A.
1
2
3
4
5
|
Session
session1 = sessionFactory.openSession(); Car
myCar = session1.get(Car. class ,
carId); //“myCar”這個時候是一個持久層對象 session1.close(); //當session關閉時,“myCar”就成爲了遊離對象 |
現在你可以把“myCar”對象傳到一直傳到表示層裏。它可以被修改並且對數據庫表沒有影響。
1
|
myCar.setColor(“Red”); //對數據庫沒有影響 |
當你需要把修改持久化到數據庫時,可以把遊離對象加入到另外一個session裏,示例如下:
1
2
3
4
5
6
7
8
9
|
Session
session2 = sessionFactory.openSession(); Transaction
tx = session2.beginTransaction(); session2.update(myCar); //遊離對象”myCar“加入到session tx.commit(); //修改被同步到數據庫 session2.close() |
Q.Hibernate怎麼區別瞬態對象(例如,剛實例化的)和遊離對象?
A.
- 如果存在”version”這個屬性的話,Hibernate會使用它來進行區別。
- 如果不存在的話,會使用標識符值(identifier value)來進行判斷。沒有標識符表示這是一個新對象。這隻適合Hibernate管理代理主鍵(surrogate key)的場景,不適合於使用自然主鍵(natural key)或者assigned代理主鍵(沒有被Hibernate管理)的場景。
- 通過InterceptorisUnsaved()來實現你自己的策略。
注意:當你重新關聯遊離的對象時,你必須保證依賴的對象也都被重新進行關聯。