ImportNew注: 本文是ImportNew編譯整理的Java面試題系列文章之一。你能夠從這裏查看所有的Java面試系列。html
Q.怎麼配置Hibernate?java
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經過單例的模式進行封裝以便於訪問。session
SessionFactory sessionFactory = new Configuration( ).configure( ).buildSessionfactory( );
Q.Session是什麼?兩個線程能共享同一個session嗎?併發
A.Session是一個輕量級非線程安全的對象(線程間不能共享session),它表示與數據庫進行交互的一個工做單元。Session是被SessionFactory建立的,在任務完成以後它會被關閉。Session是持久層服務對外提供的主要接口。Session會延遲獲取數據庫鏈接(也就是在須要的時候纔會獲取)。爲了不建立太多的session,可使用ThreadLocal來取得當前的session,不管你調用多少次currentSession()方法,返回的都是同一個session。下面是示例代碼:框架
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來整合。ide
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.
Session session1 = sessionFactory.openSession(); Car myCar = session1.get(Car.class, carId); //「myCar」這個時候是一個持久層對象 session1.close(); //當session關閉時,「myCar」就成爲了遊離對象
如今你能夠把「myCar」對象傳到一直傳到表示層裏。它能夠被修改而且對數據庫表沒有影響。
myCar.setColor(「Red」); //對數據庫沒有影響
當你須要把修改持久化到數據庫時,能夠把遊離對象加入到另一個session裏,示例以下:
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()來實現你本身的策略。
注意:當你從新關聯遊離的對象時,你必須保證依賴的對象也都被從新進行關聯。
注意:這些問題都是來自於個人《Java/J2EE Job Interview Companion》一書。