一、概述
所有的hibernate應用中都會訪問5個核心接口,它們分別是:
- Configuration:配置hibernate,創建SessionFactory對象
- SessionFactory:初始化hibernate,充當數據存儲源的代理,創建Session對象
- Session:負責保存、更新、刪除、加載和查詢對象
- Transaction:管理事事務
- Query和Criteria:執行數據庫查詢
下面將對這五個接口進行逐一總結:
二、Configuration
一個Configuration的實例允許應用指定在創建一個SessionFactory時使用的屬性和映射文件,通常一個應用將創建一個單獨的Configuration,構建一個SessionFactory的單一實例然后實例化會話線程用於服務客戶請求。Configuration僅僅是作為一個初始化時的對象,一個Configeration 實例代表Hibernate 所有Java類到Sql數據庫映射的集合。
Configuration主要用於產生SessionFactory,進行配置信息的管理,可以在configure方法中指定hibernate文件。
在Hibernate 4之前的版本中,Configuration是通過下述方式產生SessionFactory的:
SessionFactory sf=new AnnotationConfiguration().configure().buildSessionFactory();
Hibernate 4以后,Configuration的buildSessionFactory方法被標記為過時,官方建議使用buildSessionFactory(ServiceRegistry sr)這個方法來獲取SessionFactory。
Configuration configuration = new Configuration().configure(); ServiceRegistry sr=new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory = configuration.buildSessionFactory(sr);
三、SessoinFactory
SessionFactory的主要作用是產生和管理Session,通常情況下每一個應用只需要一個SessionFactory,當需要操作多個數據庫時,可以為每個數據庫指定一個SessionFactory。
一個SessionFactory的內部狀態是不可變的,一旦創建了這個內部狀態的內部設置便不再與Configuration對象關聯,這種狀態包括所有關於對象/關系映射數據。
SessionFactory在Hibernate中起到一個緩沖區的作用,它緩沖了Hibernate自動生成的SQL語句和一些其他的映射數據。
SessionFactory可以通過兩種方法getCurrentSession()和openSession()產生Session,兩種方法的區別有:
- openSession每次打開都是新的Session,並且需要人為的調用close方法關閉Session。
- getCurrentSession是從當前上下文中獲取Session並且會綁定到當前線程,第一次調用會自動創建一個Session實例,如果未手動關閉多次獲取的是同一個Session,事物提交或者回滾時會自動關閉Session。
- 使用getCurrentSession時,需要在配置文件中添加如下:
(1)如果使用的是本地事務(JDBC事務)
<property name="current_session_context_class">thread</property>
(2)如果使用的是全局事務(JTA事務)
<property name="current_session_context_class">jta</property>
備注:
全局事務:資源管理器管理和協調的事務,可以跨越多個數據庫和進程。資源管理器一般使用XA 二階段提交協議與“企業信息系統”(EIS) 或數據庫進行交互。
本地事務:在單個 EIS或數據庫的本地並且限制在單個進程內的事務。本地事務不涉及多個數據來源。
使用getCurrentSession()方法時,如果未配置上述屬性,則會報錯:
四、Session
Session用於管理一個數據庫的任務單元(增、刪、改、查),它是Java應用和Hibernate之間主要運行接口,是抽象持久性服務概念的主要API。
Session的生命周期是以一個邏輯事物的開始和結束為邊界,Session的主要功能是提供創建、讀取和刪除映射的實體類的操作,實體可能存在於三種狀態:
- 瞬時狀態(transient)
即為普通的Java對象,此狀態下,不與Session實例關聯,在數據庫中沒有和瞬時對象關聯的數據
2. 持久狀態(persistent)
處於此狀態的實例在數據庫中對應的記錄,並擁有一個持久化標識。持久狀態的對象總是與Session和Transaction相關聯,在一個Session中,對持久對象的改變不會馬上對數據庫進行變更,而是發生在Transaction終止,執行commit之后。
3. 游離狀態(detached)
與持久狀態的對象關聯的Session被關閉后,該對象就變成游離狀態,此狀態下對游離對象的引用依然有效,也可以繼續被修改。
這三種狀態之間可以相互轉換,如下圖示:
Session中有一個緩存,被稱為hibernate的第一季緩存,它存放被當前工作單元加載的對象,這塊緩存中有一map,在執行save方法后,會生成一個id,這個id會保存在map的key中,與之對應的value值就是該是該對象的引用,執行commit()方法后,數據庫就有對應這條數據了,此時該實體處於持久化狀態,當執行完Session.close()后,處於托管狀態。
區分這三種狀態的關鍵在於:
- 有沒有ID
- ID在數據庫中有沒有
- 在內存中沒有
瞬時狀態下,為內存中一個對象沒有ID,緩存中也沒有
持久化狀態,內存有,緩存中有,數據庫中也存在
托管狀態:內存中有,緩存中沒有,數據庫中存在ID
Session接口有幾個重要的方法:
save():持久化給出的瞬時狀態的實體,並分配有一個ID標識符
@Test public void test() { Session session=HibernateUtil.getSessionFactory().getCurrentSession(); Book b=new Book(); b.setBookName("Java"); b.setId(1); b.setPrice(21); session.beginTransaction(); session.save(b); session.getTransaction().commit(); }
Delete():從數據庫中刪除持久化實體
@Test public void test() { Session session=HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Book b=(Book) session.get(Book.class, 1); session.delete(b); session.getTransaction().commit(); }
load():返回給定標識符的實體類的持久化實例(假定實例存在),不能使用該方法來確定一個實例是否存在(使用get方法)
@Test public void test() { Session session=HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Book b=(Book) session.load(Book.class, 1); System.out.println(b.getBookName()); session.getTransaction().commit(); }
get():返回給定標識符的實體類的持久化實例或null(如果實例不存在)
@Test public void test() { Session session=HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Book b=(Book) session.get(Book.class, 1); session.getTransaction().commit(); System.out.println(b.getBookName()); }
get()和load()方法的區別:
- 當對應記錄不存在時,使用load方法會報異常,而get方法會返回null
2. load返回的是代理對象,等到真正用到對象的內容時才發出sql語句,而get直接從數據庫加載,不會延遲
update():更新指定標識符的托管狀態實例為持久化狀態,如果存在具有相同標識符的持久化實例,將會報異常
五、Transaction
Hibernate的Transaction是底層的JDBC Transaction或者JTA Transaction的封裝,具體取決於在hibernate.properties中的配置。
一個典型的事務在創建完Session對象后即使用beginTransaction()啟動事務,從此開始知道commit()之間的代碼都會處於同一個事務中,這兩個函數之間的所有的數據庫代碼都會在commit()執行時一次性提交,在提交時如果某一句代碼執行出現異常,就會回滾這一次事務之間的所有執行代碼。
六、Query
通過SessionFactory獲得了session對象后,除了可以通過get(類名.class, id)方法得到相應的對象,還可以通過獲得Query對象來取得需要的對象:
Query query = session.createQuery("查詢語句如from UserBean"); List list = query.list();//得到一個集合 query.uniqueResult();//得到一個單個的對象
分頁查詢:
query.setFirstResult(位置);//表示從哪個位置開始查詢,返回query對象 query.setMaxResult(記錄條數);//表示當頁共幾條記錄,返回一個集合 session.createQuery("select count(*) from 類名").uniqueResult();//得到記錄總數
查詢語句同sql查詢語句很相像,只是將表名換作類名,字段名換作屬性名,如果查詢需要條件可以使用占位符來替換對應的屬性名,也可以使用:變量名來作為占位符。
eg:
@Test public void test1() { Session session=HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Query q=(Query) session.createQuery("from Person"); List<Person> persons=(List<Person>)q.list(); for(Person p:persons) System.out.println(p.getName()); session.getTransaction().commit(); }
public void test2() { Session session=HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Query q=(Query) session.createQuery("select count(*) from Person");//得到記錄總數 int count=((Long)q.uniqueResult()).intValue(); System.out.println(count); session.getTransaction().commit(); }