天天看點

操縱持久化對象

操縱持久化對象                                                          ++YONG原創,轉載請注明 1.    了解Session的緩存: 在Java裡面,緩存通常是指Java對象的屬性占用的記憶體空間,通常是一些集合類型的屬性。在session接口的實作類SessionImpl中定義了一系列的Java集合,這些Java集合就構成了Session的緩存。 當Session的save()方法持久化一個對象時,這個對象被加入到Session的緩存中,以後即使應用程式中的引用變量不再引用這個對象,隻要Session的緩存還沒有被清空,這個對象仍然處于生命周期中。當Session的load()方法加載一個對象時,Session會先判斷緩存中是否已經存在這個對象了,如果存在,就不需要再到資料庫中重新加載了。 Session的緩存有兩大作用: 1.1.        減少通路資料庫的頻率。 1.2.        保證緩存中的對象與資料庫中的相關記錄保持同步。 Session有兩個方法:一個commit()事務送出方法,還有flush()重新整理緩存方法,都有着清理緩存的作用。flush()進行緩存的清理,執行一系列的SQL語句,但不會送出事務。而commit()方法會先調用flush()方法,然後在送出事務。 2.    定義持久化類的建議: 在應用程式中,用來實作業務問題實體的(如,在電子商務應用程式中的Customer和Order) 類就是持久化類。如果這些持久化類遵循一些簡單的規則,Hibernate能夠工作得更好,這些規則也被稱作簡單傳統Java對象(POJO:Plain Old Java Object)程式設計模型。但是這些規則并不是必需的。最好要遵循以下幾條主要的規則: 1)      實作一個預設的(即無參數的)構造方法(constructor): 我們強烈建議,在Hibernate中,為了運作期代理的生成,構造方法至少是 包(package)内可見的。 2)      提供一個辨別屬性(identifier property): 我們建議你對持久化類聲明命名一緻的辨別屬性。我們還建議你使用一個可以為空(也就是說,不是原始類型)的類型。 3)      使用非final的類: 代理(proxies )是Hibernate的一個重要的功能,它依賴的條件是,持久 化類或者是非final的,或者是實作了一個所有方法都聲明為public的接口。你也應該避免在非final類中聲明

public final

的方法。 4)      為持久化字段聲明通路器(accessors): 5)      如果你有如下需求,你必須重載 equals() 和 hashCode()方法: l 想把持久類的執行個體放入Set中(當表示多值關聯時,推薦這麼做) l 想重用脫管執行個體 Hibernate保證,僅在特定會話範圍内,持久化辨別(資料庫的行)和Java辨別是等價的。是以,一旦 我們混合了從不同會話中擷取的執行個體,如果希望Set有明确的語義,就必須實作equals() 和hashCode()。 3.    持久化對象的三種狀态: 一個持久化類的執行個體可能處于三種不同狀态中的某一種。 3.1.    瞬時(transient)狀态: 該執行個體是剛用new語句建立的,還沒有被持久化,不處于任何Session的緩存中。它沒有持久化辨別(相當于主鍵值)。處于瞬時狀态的執行個體被稱為瞬時對象。它的特點是: 不和任何一個Session執行個體關聯。在資料庫中沒有對應的記錄。 3.2.    持久化 (persistent) 狀态: 已經被持久化,加入到Session緩存中。處于持久化狀态的執行個體被稱為持久化對象。 執行個體目前與某個Session有關聯。 它擁有持久化辨別(相當于主鍵值),并且可能在資料庫中有一個對應的行。 Hibernate保證在同一個Sesion執行個體的緩存中,資料庫中的每條記錄隻對應唯一的持久化對象。 它的特點是:        持久化對象總是被一個Session執行個體關聯。持久化對象和資料庫中的相關記錄對應。Session在清理緩存時,會根據持久化對象的屬性變化,來同步更新資料庫。 3.3.    脫管(detached) 狀态: 已經被持久化過,但不再處于Session的緩存中。處于脫管狀态的執行個體被稱為脫管對象。執行個體曾經與某個持久化上下文發生過關聯,不過那個上下文被關閉了, 或者這個執行個體是被序列化(serialize)到另外的程序。 它擁有持久化辨別,并且在資料庫中可能存在一個對應的行。 對于脫管狀态的執行個體,Hibernate不保證任何持久化辨別和Java辨別的關系。它的特點是: 不再位于session的緩存中,即它不再和session關聯。它擁有持久化辨別。

操縱持久化對象

4.    Session的儲存、删除、更新和查詢方法: 4.1.    Session的save()方法:使用一個臨時對象轉變為持久對象。 方法簽名:public Serializable save(Object object) throws HibernateException; 它完成以下操作: 1)      把持久化類的執行個體加入到緩存中,使它變為持久化對象。 2)      選用映射檔案指定的辨別符生成器為持久化對象配置設定唯一的OID。 3)      計劃執行一個insert語句,把持久化對象目前的屬性值組裝到insert 語句(SQL DML)中。值得注意的是,save()方法并不是立即執行SQL insert語句。隻有當Session清理緩存時,才會執行SQL insert語句。 另外,需要注意的是:Hibernate通過持久化對象的OID來維持它和資料庫相關記錄的對應關系。是以當持久化的執行個體處于持久化狀态時,不允許程式随意修改它的OID。其實,無論java對象處于瞬時狀态、持久化狀态還是脫管狀态,程式都不應該修改它的OID。 4.2.    Session的update()方法:使一個脫管對象轉變為持久化對象。 方法簽名:public void update(Object object) throws HibernateException; 它完成以下操作: 1)      把脫管對象重新加入到Session緩存中,使它變為持久化對象。 2)      計劃執行一個update語句。值得注意的是,Session隻有在清理緩存的時候才會執行update語句,并且在執行時才會把持久化對象目前的屬性值組裝到update語句中。 4.3.    Session的saveOrUpdate()方法:        方法簽名:public void saveOrUpdate(Object object) throws HibernateException ; saveOrUpdate()方法同時包含了save()與update()方法的功能,如果傳入的參數是瞬時對象,就調用save()方法;如果傳入的參數是脫管對象,就調用update()方法;如果傳入的參數是持久化對象,方法就直接傳回。那麼,saveOrUpdate()方法如果判斷一個對象處于瞬時狀态不是脫管狀态呢?如果滿足以下情況之一,Hibernate就把它作為臨時對象: 1)      Java對象的OID取值為null。 2)      Java對象具有version屬性,并且取值了null。 3)      在映射檔案中為<id>元素設定了unsaved-value屬性,并且OID取值與unsaved-value屬性值比對。 4)      在映射檔案中為<version>元素設定了unsaved-value屬性,并且version屬性取值與unsaved-value屬性值比對。 5)      自定義了Hibernate的Interceptor實作類,并且Interceptor的isUnsaved()方法傳回Boolean.TRUE。 4.4.    Session的delete()方法: 方法簽名:public void delete(Object object) throws HibernateException; delete()方法用于從資料庫中删除與Java對象對應的記錄。如果傳入的參數是持久化對象,Session就計劃執行一個delete語句。如果傳入的參數是遊離對象,先使遊離對象被Session關聯,使它變為持久化對象,然後計劃執行一個delete語句。值得注意的也是,Session隻有在清理緩存的時候才會執行delete語句。 5.    通過主鍵ID取得資料對象: 5.1.    Session的get()方法:        方法簽名:public Object get(Class clazz, Serializable id) throws HibernateException; 根據給定的OID從資料庫中加載一個持久化對象,若資料庫中不存在與OID對應的記錄,此方法傳回null。        get()方法的執行順序如下: 1)      首先通過id在session緩存中查找對象,如果存在此id主鍵值的對象,直接将其傳回。如果不存在,将進行第2步。 2)      在二級緩存中查找,找到後将其傳回。 3)      如果在session緩存和二級緩存中都找不到此對象,剛從資料庫加載擁有此id的對象。如果資料庫也不存在這個擁有此id的對象,則傳回null。 5.2.    Session的load()方法: 方法簽名:public Object load(Class theClass, Serializable id) throws HibernateException; 根據給定的OID從資料庫中加載一個持久化對象,若資料庫中不存在與OID對應的記錄,此方法将抛出org.hibernate.ObjectNotFoundException異常。 對于get和load的根本差別,一句話,hibernate對于load方法認為該資料在資料庫中一定存在,可以放心的使用代理來延遲加載,如果在使用過程中發現了問題,隻能抛異常;而對于get方法,hibernate一定要擷取到真實的資料,否則傳回null。 6.    Query接口: Hibernate提供Query接口,它用來執行HQL語句。 6.1.    綁定參數 6.1.1.       使用 “?” 按參數位置綁定: 通過Query接口執行HQL語句時,可以先設定查詢參數,然後通過setXXX()方法來綁定參數。如下

Query query = session.createQuery("from User as u where u.age > ? and u.name like ?"); query.setInteger(0, 25); query.setString(1, "%a%"); List list = query.list();

Hibernate提供了綁定各種類型的參數的方法,如參數為字元串類型,可調用setString(),如果參數為整數類型,可調用setInteger()方法,以此類推。這些setXXX()方法的第1個參數HQL查詢語句中參數的位置,第2個參數代表HQL查詢語句中參數的值。 6.1.2.       使用 “:” 後跟變量名來 按命名參數綁定: 可以使用命名參數來取代使用“?”設定參數的方法,這可以不用依照特定的順序來設定參數值,如上例可改成:

Query query = session.createQuery("from User as u where u.age > :minAge and u.name like likeName"); query.setInteger("minAge", 25); query.setString("likeName", "%a%"); List list = query.list();

使用命名參數方式的綁定方式有以下優勢: 1)      代碼可讀性更好。 2)      命名參數不依賴它們在查詢字元串中出現的位置。 3)      在同一個查詢中可以多次使用。 是以,應該優先考慮使用命名參數方式。 6.2.    使用命名查詢(nameQuery): 可以将HQL語句編寫在程式之外,以避免寫死在程式之中,這樣要修改HQL語句時就很友善。在xxx.hbm.xml中使用<qiuery/>标簽,并在<![CDATA[ 與 ]]> 之間編寫HQL,如下Student.hbm.xml:

...... < hibernate-mapping >     < class name = "org.qiujy.demo.User" table = "user" >         < id name = "id" column = "id" type = "java.lang.Integer" >             < generator class = "native" />         </ id >         < property name = "name" column = "name" type = "java.lang.String" />         < property name = "age" column = "age" type = "java.lang.Integer" />     </ class > <query name= "queryUserByAgeAndName">     <![CDATA[     from User as u where u.age >:minAge and u.name like :likeName ]]> </query> </ hibernate-mapping >

在代碼中這樣來調用:

Query query = session.getNamedQuery( "queryUserByAgeAndName"); query.setInteger("minAge", 25); query.setString("likeName", "%a%"); List list = query.list();

6.3.    Query接口的list()方法: Query接口的list()方法用于取得一個List類的執行個體,此執行個體中包括的可能是一個對象集合,也可能是一個對象數組集合。最常見的使用是用list()方法來取得一組符合執行個體對象。如上示例。 6.4.    Query接口的uniqueResult()方法: 當确信使用的HQL語句查詢時傳回的集合中 隻有一個對象時,就可以使用這個方法。但如果傳回結果中有多個對象,使用這個方法會抛出org.hibernate.NonUniqueResultException 異常,說“query did not return a unique result”。