hql語句的語法

hql語句的語法

 

1、HQL查詢的from子句數據庫

from是最簡單的語句,也是最基本的HQL語句。from關鍵字後緊跟持久化類的類名。數組

例如:緩存

from Person  代表從Person持久化類中選出所有的實例session

推薦爲Person持久化類的每一個實例起別名,例如:併發

from Person as papp

p做爲Person的實例的別名,所以也應該遵照Java的命名規則:第一個單詞的首字母小寫,後面每一個單詞的首字母大寫。函數

命名別名時,as關鍵字是可選的,但爲了增長可讀性,建議保留。工具

from 後還可同時出現多個持久化類,此時將產生一個笛卡爾積或跨表的鏈接,但實際上這種用法不多使用,由於一般咱們可能須要使用跨表的鏈接,此時能夠考慮使用隱式鏈接或顯示鏈接,而不是直接在from後緊跟多個表名。fetch

2、關聯和鏈接ui

       Hibernate使用關聯映射來處理底層數據表之間的鏈接,一旦咱們提供了正確的關聯映射後,當程序經過Hibernate進行持久化訪問時,將可利用Hibernate的關聯來進行鏈接。

      HQL支持兩種關聯鏈接(join)的形式:隱式(implicit)與顯示(explicit)。

隱式鏈接形式不適用join關鍵字,使用英文點號(.)來隱式鏈接來關聯實體,而Hibernate底層將自動進行關聯查詢。以下HQL語句:

from Person p where p.myEvent.title > :title

上面的p.myEvent屬性的實質是一個持久化實體,所以Hibernate底層隱式地自動進行鏈接查詢。

顯示鏈接則須要使用xxx join關鍵字,例如以下語句:

//使用顯示鏈接

from Person p

inner join p.myEvent event

where event.happenDate < :endDate

使用顯示鏈接時,能夠爲相關聯的實體,甚至是關聯集合中的所有元素指定一個別名。

Hibernate支持的HQL鏈接類型,可以使用以下幾種鏈接方式:

inner join(內鏈接),可簡寫成join。

left outer join(左外鏈接),可簡寫成left join。

right outer join(右外鏈接),可簡寫成right join。

full join(全鏈接),並不經常使用。

使用顯示鏈接時,還可經過HQL的with關鍵字來提供額外的鏈接條件,例如以下HQL語句:

from Person p

inner join p.myEvent event

with p.id > event.id

where event.happenDate < :endDate

       HQL語句中的with關鍵字的做用基本等同於SQL99中on關鍵字的做用:都是用於指定鏈接條件。經過在HQL語句中使用with關鍵字,可讓HQL語句執行非等值鏈接查詢。

      因爲錶鏈接的方式都是基於底層SQL來實現的,若是底層不支持這些外鏈接,那麼執行對應的HQL時就會相應地引起異常。

 

3、隱式鏈接和顯示鏈接有以下兩點區別:

(1)隱式鏈接底層轉換成SQL92的內鏈接,顯示鏈接層將轉換成SQL99的多表鏈接。

(2)隱式鏈接和顯示鏈接查詢後返回的結果不一樣。

當HQL語句中省略select關鍵字時,使用隱式鏈接查詢返回的結果是多個被查詢實體組成的集合。

當HQL語句中省略select關鍵字時,使用顯示鏈接查詢返回的結果也是集合,但集合元素是被查詢持久化對象、全部被關聯的持久化對象所組成的數組。

 注意:

       對於Hibernate3.2.3之後的版本,若是關聯實體是單個實體或單個的組件屬性,HQL依然能夠彷佛用英文點號(.)來隱式鏈接關聯實體或組件;但若是關聯實體是集合(包括1-N關聯、N-N關聯和集合元素時組件等),則必須使用xxx join來顯示鏈接關聯實體或組件。

       對於集合屬性的,Hibernate默認採用延遲加載策略,解決辦法:

       (2.1)能夠在Hibernate映射文件中指定lazy="false"來關閉延遲加載。

       (2.2)使用join fetch,一般無須指定別名,由於相關聯的對象不該當在where子句(或其餘任何子句)中使用。並且被關聯的對象也不會再被查詢的結果中直接返回,而是應該經過其父對象來訪問。

使用fetch關鍵字時,有以下幾個注意點:

       fetch不該該與setMaxResults()或setFirstResult()共用。由於這些操做是基於結果集的,而在預先抓取集合類時可能包含重複的數據,即沒法預先知道精確的行數。

       fetch不能與獨立的with條件一塊兒使用。

       若是在一次查詢中fetch多個集合,能夠查詢返回笛卡爾積,所以請多加註意。

       對bag映射而言,同時join fetch多個集合時可能出現非預期結果,所以須要謹慎使用。

      full join fetch 與right join fetch是沒有任何意義的。

程序裏但願預加載那些本來應延遲加載的屬性,則能夠經過fetch all properties來強制Hibernate當即抓取這些屬性。例如:

from Document fetch all properties order by name

 

4、HQL查詢的select子句

(1)select子句用於選擇指定的屬性或直接選擇某個實體,固然select選擇的屬性必須是from後持久化類包含的屬性。

例如:

select p.name from Person as p

(2)select能夠選擇任意屬性,即不只能夠選擇持久化類的直接屬性,還能夠選擇組件屬性包含的屬性。例如:

select p.name.firstName from Person as p

(3)在特殊狀況下,若是select後只有一項(包括持久化實例或屬性),則查詢獲得的集合元素就是該持久化實例或屬性。

(4)若是select後有多個項,則每一個集合就是選擇出的多項組成的數組。

例如:

select p.name,p from Person as p

執行該HQL語句獲得的集合元素時相似於[String,Person]結構的數組,其中第一個元素時Person實例的name屬性,第二個元素時Person實例。

注意:即便select後的列表項選出某個持久化類的所有屬性,這些屬性依然是屬性,Hibernate不會將這些屬性封裝成對象。只有在select後的列表裏給出持久化類的別名(其實就是實例名),Hibernate纔會將該項封裝成一個持久化實體。

(5)select支持將選擇出的屬性存入一個List對象中。

例如:

select new list(p.name, p.address) from Person as p

 (6)select支持將選擇出的屬性封裝成對象,前提是該對象擁有支持這些屬性的構造器。

例如:

select new ClassTest(p,name, p.address) from Person as p;

而ClassTest必須有以下的構造器:ClassTest(String s1, String s2)

(7)select還支持給選中的表達式命名別名。例如:

select p.name as personName from Person as p

這種用法與new map 結合使用更廣泛。例如:

select new map(p.name as personName) from Person as p

執行上面的HQL語句返回的結果是集合,其中集合元素時Map對象,以personName做爲Map的key,實際選出的值做爲Map的value。

 

 

5、HQL查詢的彙集函數

HQL支持的彙集函數與SQL的徹底相同:avg,count,max,min,sum。

例如,以下的HQL語句:

select count(*) from Person

select max(p.page) from Person as p

select子句還支持字符串鏈接符、算術鏈接符,以及SQL函數。例如:

select p.name||""||p.address from Person as p

select子句也支持使用distinct和all關鍵字,此時的效果與SQL的效果徹底相同。

 

 

6、多態查詢

       HQL語句被設計成可以理解多態查詢,from後跟持久化類名,不只會查詢出該持久化類的所有實例,還會查詢出該類的子類的所有實例。

以下面的查詢語句:from Person as p

       若是Named接口有多個持久化實現類,下面的語句將返回這些持久化類的所有實例。

以下面的查詢語句:from Named as n

注意:上面最後一條查詢,須要多個SQL SELECT 語句,所以沒法使用order by子句對結果集排序,從而不容許對這些查詢結果使用Query.scroll()方法。

 

 

7、HQL查詢的where子句

(1)where子句用於篩選選中的結果,縮小選擇的範圍。若是沒有爲持久化實例命名別名,則能夠直接使用屬性名來引用屬性。

以下面兩條HQL語句:

from Person where name like "tom%"

form Person as p where p.name like "tom%"

(2)複合屬性表達式增強了where子句的功能,例如,以下的HQL語句:

from Cat cat where cat.mate.name like "kit%"

上面語句被翻譯成如下含有內鏈接的SQL查詢:

select * from cat_table as table1 cat_table as table2

where table1.mate = table2.mate

and table1.name like '''kit%'"

實際上這種用法使用了隱式鏈接查詢,從Hibernate3.2.3以後,只有當cat,mate屬性引用的是普通組件屬性或者單獨的關聯實體時纔可接着在後面使用點好(.)來引用mate屬性,如cat,mate.name; 若是cat,mate是集合屬性,Hibernate3.2.3之後的版本不支持這種用法。

"="號不只能夠被用來比較屬性的值,也能夠用來比較實例。

select cat,mate from Cat cat, Cat mate where cat.mate = mate

(3)在進行多態持久化的狀況下,class關鍵字用來存取一個實例的鑑別值。嵌入where子句的Java類名,將被做爲該類的鑑別值。

//執行多態查詢時,默認會選出Cat及其全部子類的實例

//在以下HQL語句中,將只選出DomesticCat類的實例

from Cat cat where cat.class = DomesticCat

(4)當where子句中的運算符只支持基本類型或者字符串時,where子句中的屬性表達式必須以基本類型或者字符串結尾,不要使用組件類型屬性結尾,例如Account和Person屬性,而Person有Name屬性,Name屬性有firstName屬性。

以下所示:

//firstName是字符串

from Account as a where a.person.name.firstName like "dd%"

//下面是錯誤實例

from Account as a where a.person.name like "dd%"

 

 

8、表達式

一、HQL的功能很是豐富,where子句後支持的運算符,不只包括SQL的運算符,也包括EJB-QL的運算符等。

where子句中容許使用大部分SQL支持的表達式,包括以下種類:

(1)字符串鏈接:如value1||value2,或使用字符串鏈接函數concat(value1, value2)

(2)簡單的case,case...when...then...else...end和case,case when...then...else...end等。

(3)時間操做函數:current_date()、current_time、year()等。

(4)EJB-QL3.0的函數:substring()、trim()、abs()、sqrt()等。

(5)可在where子句中使用SQL常量。

(6)在HQL語句中使用Java中的public static final類型的常量,例如Color.RED

(7)HQL語句支持使用英文問號(?)做爲參數佔位符,這與JDBC的參數佔位符一致;也使用命名參數佔位符號,方法在參數名前加英文冒號(:),例如:start_date等。

(8)若是底層數據庫支持單行函數,則HQL語句也徹底能夠支持。

(9)支持數據庫的類型轉換函數,如cast(... as ...),第二個參數是Hibernate的類型名,或者extract(... from ,,,),前提是底層數據庫支持ANSI cast()和extract()。

二、若是在Hibernate配置文件中進行以下聲明:

<property name="hibernate.query.substitutions">true 1,false 0</property>

上面的聲明代表:HQL轉換SQL語句時,將使用字符1和0來取代關鍵字true和false,而後將能夠在表達式中使用布爾表達式。

三、有用的elements()和indices函數,用於返回指定集合的全部元素和全部索引。

四、在where子句中,有序集合(數組、List集合、Map對象)的元素能夠經過【】運算符來訪問。以下:

from Order order where order.items[0].id=1234

在【】中的表達式甚至能夠是一個算式表達式。

五、結構變量:size、elements、indices等,只能在where子句中使用。

 

 

9、order by子句

查詢返回的集合根據類或組件屬性的任何屬性進行排序。例如:

from Person as p order by p.name,p.age

還可使用as或desc關鍵字指定升序或降序的排序規則。例如:

from Person as p order by p.name asc,p.age desc

若是沒有指定排序規則,默認採用升序規則。

10、group by子句

返回彙集值的查詢能夠對持久化類或組件屬性的進行分組,分組使用group by子句。看下面的HQL查詢語句:

select cat,color,sum(cat.weight),count(cat) from Cat cat group by cat.color

其規則相似於SQL規則。

having子句用於對分組進行過濾,以下所示:

select cat,color,sum(cat.weight),count(cat) from Cat cat group by cat.color having cat.color in (eg.Color.TABBY,eg.Color.BLACK)

注意:group by子句與order by 子句中都不能包含算術表達式

 

 

11、子查詢

(1)若是底層數據庫支持子查詢,則能夠在HQL語句中使用子查詢。以下:

from Cat as fatcat where fatcat.weight > (select avg(cat.weight) from DomesticCat cat)

(2)若是子查詢是多行結果集,則應該使用多行運算符。以下:

from Cat as cat where not(cat.name, cat.color) in (select cat.name, cat.color from DomesticCat cat)

(3)SQL語法中子查詢還能夠出如今select子句以後,HQL也支持這種用法,看以下HQL語句:

select cat.id,(select max(kit.weight) from cat.kitten kit)

from Cat as cat

注意:HQL子查詢只能夠在select子句或者where子句中出現。

 

12、命名查詢

HQL支持將查詢所用的HQL語句放入配置文件中,而不是代碼中。

在Hibernate映射文件的<hibernate-mapping/>元素中使用<query/>子元素來定義命名查詢,使 用<query/>元素只須要指定一個name屬性,指定該命名查詢的名字。該元素的內容就是命名查詢的HQL語句。以下配置文件片斷:

<query name="myNameQuery">

        from Person as p where p.age > ?

</query>

配置好後,經過Session提供的一個getNameQuery(String name)方法,該方法用於建立一個Query對象,剩下的操做與普通HQL徹底同樣。以下所示:

List p1 = sess.getNamedQuery("myNameQuery").setInteger(0,20).list()

 

 

十3、條件查詢

條件查詢經過以下3個類完成:

Criteria:表明一次查詢。

Criterion:表明一個查詢條件。

Restrictions:產生查詢條件的工具類。

執行條件查詢的步驟以下:

(1)得到Hibernate的Session對象。

(2)以Session對象建立Criteria對象。

(3)使用Restrictions的靜態方法建立Criterion查詢條件。

(4)向Criteria查詢中體檢Criterion查詢條件。

(5)執行Criteria的list等方法返回結果集。

代碼片斷以下:

List l = session.createCriteria(Student.class)

            //此處增長限制條件必須是Student已經存在的屬性

             .add(Restrictions.get("studentNumber", 20050231L))

            //若是要增長對Student的關聯類的屬性的限制

            //則必須從新createCriteria()

            //若是此關聯屬性是集合,則只要集合裏任意一個對象的屬性知足下面條件便可

            .createCriteria("enrolments")

            .add(Restrictions.gt("semester",2))

            .list();

在條件查詢中,Criteria接口表明依次查詢,該查詢自己不具有任何的數據篩選功能,Session調用createCriterial(Class clazz)方法對某個持久化類建立條件查詢實例。

Criteria對象不具有任何的數據篩選功能,但程序能夠經過向Criteria對象中組合多個Criterion(每一個Criterion對象表明一個過濾條件)便可實現數據過濾了。

Criterion接口表明一個查詢條件,該查詢條件由Restrictions負責產生。Restrictions是專門用於產生查詢條件的工具類,它的方法大部分都是靜態方法,經常使用的方法以下:

(1)static Criteion allEq(Map propertyNameValues):判斷指定屬性(由Map參數的key指定)和指定值(由Map參數的value指定)是否徹底相等。

(2)static Criterion between(String propertyName, Object lo, Object hi):判斷屬性值在某個指範圍以內。

 

 

十4、關聯和動態關聯

代碼片斷以下:

List l = session.createCriteria(Student.class)

            //此處增長限制條件必須是Student已經存在的屬性

             .add(Restrictions.get("studentNumber", 20050231L))

            //若是要增長對Student的關聯類的屬性的限制

            //則必須從新createCriteria()

            //若是此關聯屬性是集合,則只要集合裏任意一個對象的屬性知足下面條件便可

            .createCriteria("enrolments")

            .add(Restrictions.gt("semester",2))

            .list();

上面的代碼表示創建Person類的條件查詢,第一個查詢條件是直接過濾Person的屬性。第二個查詢條件則過濾Person的關聯實體的屬性,其中 enrolments是Person類的關聯實體,而semester則是Enrolment類的屬性。值得注意的是,返回的並非Enrolment對 象,而是Person對象的集合。

注意:使用關聯類的條件查詢,依然是查詢原有持久化類的實例,而不是查詢被關聯類的實例。

可以使用條件查詢支持的替換形態,將上面查詢代碼替換成以下形式:

List l = session.createCriteria(Student.class)

            .add(Restrictions.gt("studentNumber",20050231L))

            .createAlias("enrolments","en")

            .add(Restrictions.gt("semester",2))

             .list();

createAlias()方法並不建立一個新的Criteria實例,它只是給關聯實體(包含集合裏包含的關聯實體)起一個別名,讓後面過濾條件可根據關聯實體進行篩選。

在默認狀況下,條件查詢將根據映射文件指定的延遲加載策略來加載關聯實體,若是但願在條件查詢中改變延遲加載策略(就像在HQL查詢中使用fetch關鍵 字同樣),那就可經過Creteria的setFetchMode()方法來實現,該方法接受一個FetchMode參數。

FetchMode裏有幾個常量,以下:

DEFAULT:使用配置文件制定的延遲加載策略處理。

JOIN:使用外鏈接,預初始化全部關聯實體。

SELECT:啓用延遲加載,系統將使用單獨的select語句來初始化關聯實體。只有當個真正訪問關聯實體的時候,纔會執行第二條select語句。

初始化Student對象時,也能夠初始化Student關聯的Enrolment實體,實體使用以下代碼:
List l = session.createCriteria(Student.class)

            .add(Restrictions.gt("studentNumber",20050231L))

            .setFetchMode("enrolments", FetchMode.JOIN)

            .list();

 

 

十5、投影、聚合和分組

投影運算實際上就是一個基於列的運算,一般用於投影到指定列(也就是過濾其餘列,相似select子句的做用),還能夠完成SQL語句中經常使用的分組、組篩選等功能。

Hibernate的條件過濾中使用Projection表明投影運算,Projection是一個接口,而Projections做爲Projection的工廠,負責生成Projection對象。

一旦產生了Projection對象以後,就可經過Criteria提供的setProjection(Projection projection)方法來進行投影運算。從該方法上看,每一個Criteria只能接受一個投影運算,彷佛沒法進行多個投影運算,但實際上 Hibernate又提供了一個ProjectionList類,該類是Projection的子類,並能夠包含多個投影運算,經過這種方式即完成多個投 影運算。

所以,一個條件查詢的投影運算一般有以下程序結構:

List cats = session.createCriteria(Cat.class)

                 .setProjection(Projections.projectionList()

                 .add(Projections.rowCount())

                 .add(Projections.avg("weight"))

                 .add(Projections.groupProperty("color"))

                  ).addOrder(Order.asc("color"))

                  .list();

注意:使用條件查詢的投影運算時,不能使用顯示的分組子句,但某些投影類型的實質就是分組投影,這些投影元素將出如今SQL的group by子句中——如上的groupProperty("color")投影。

投影運算的實質和group by子句、彙集函數的功能大體一致。

除此以外,若是咱們但願對分組(投影)後屬性進行排序,那就須要爲投影運算指定一個別名。爲投影運算指定別名有3種方法:

(1)使用Projections的alias()方法爲指定投影指定別名。一旦爲projection指定了別名,則程序就能夠根據該Projection別名來進行其餘額外操做了,好比排序。條件查詢片斷以下:

List l = session.createCriteria(Enrolment.class)

           .setProjection(Projections.projectionList()

            //按course進行分組

           .add(Projections.groupProperty("course"))

           //統計記錄條數,併爲統計結果指定別名c

           .add(Projections.alias(Projections.rowCount()," c"))

             ).addOrder(Order, asc("c"))

           .list();

(2)使用SimpleProjection的as()方法爲自身指定別名。

List l = session.createCriteria(Enrolment.class)

           .setProjection(Projections.projectionList()

            //按course進行分組

           .add(Projections.groupProperty("course").as("c"))

           //統計記錄條數,併爲統計結果指定別名c

           .add(Projections.rowCount())

             ).addOrder(Order, asc("c"))

           .list();

(3)使用ProjectionList的add()方法添加投影時指定別名。

ProjectionList的add()方法有兩個重載形式,一個是直接添加投影,另外一個是在添加投影時指定別名。條件查詢片斷以下:

List l = session.createCriteria(Enrolment.class)

           .setProjection(Projections.projectionList()

            //按course進行分組,指定別名爲c

           .add(Projections.groupProperty("course"),("c"))

           //統計記錄條數,併爲統計結果指定別名rc

           .add(Projections.rowCount(),"rc")

             ).addOrder(Order, asc("c"))

           .list();

除此以外,Hibernate還提供了Property執行投影運算,Property投影的做用相似於SQL語句中的select,條件查詢的結果只有被Property投影的列纔會被選出,條件查詢片斷以下:

List l = session.createCriteria(Student.class)

            .setProjection(Property.forName("name"))

            .list();

上面條件查詢執行的結果再也不是Student對象集合,而是name屬性所組成的集合。

 

 

十6、離線查詢和子查詢

條件查詢的離線查詢由DetachedCriteria來表明,DetachedCriteria類使你在一個session範圍以外建立一個查詢,而且可使用任意的Session來執行它。

DetachedCriteria還可表明子查詢,當咱們把DetachedCriteria傳入Criteria中做爲查詢條件時,DetachedCriteria就變成了子查詢。如下代碼片斷所示:

//定義一個離線查詢

DetachedCriteria query = DetachedCriteria.forClass(Student.class)

                                         .forClass(Student.class)

                                         .setProjection(Property.forName("name"));

//打開Session和事務(省略)

//執行離線查詢

List l = query.getExecutableCriteria(session).list();

//執行子查詢

List l = session.createCriteria(Student.class)

           .add(Property.forName("name").in(query))

           .list();

若是程序使用Session的getExecutableCriteria()方法來執行DetachedCriteria對象,則它被當成離線查詢使用;若是程序使用Property的系列方法來操做DetachedCriteria對象,則它被當成子查詢使用。

 

 

十7、事務和Session

一、Session和用戶請求是一對一得關係,這是一種理想的Session管理模式。

爲了達到這種效果,推薦使用一個ThreadLocal變量,把Session綁定處處理客戶端請求的線程上。這種方式可讓運行在該線程上的全部程序代 碼輕鬆地訪問Session。也能夠在一個ThreadLocal變量中保持事務上下文環境,不過這依賴於你所選擇的數據庫事務劃分機制。這種實現模式被 稱爲ThreadLocal Session和Open Session in View。

工具類代碼以下:
public class HibernateUtil

{

       //使用一個final變量來保存不可變的SessionFactory

       public static final SessionFactory sessionFactory;

static{

         try{

             //採用默認的Hibernate.cfg,xml來啓動一個Configuration的實例

             Configuration conf = new Configuration().configure();

             //由conf實例建立一個SessionFactory實例

             sessionFactory = conf.buildSessionFactory();

             }catch(Throwable ex){

                     System.err.println("初始化SessionFactory出現異常:"+ex);

                     throw new ExceptionInitializerError(ex);

            }

         }

//ThreadLocal是隔離多個線程的數據共享

//不存在多個線程之間共享資源,所以再也不須要對線程同步

          public static final ThreadLocal session = new ThreadLocal();

          public static Session currentSession() throws HibernateException

          {

                Session s = (Session)session.get();

                //若是該線程尚未Session,則建立一個新的Session

                if(s == null)

                {

                    s = sessionFactory.openSession();

                //將得到的Session變量存儲在ThreadLocal變量session裏

                     session.set(s);

                 }

                 return s;

           }

           public static void closeSession() throws HibernateException

           {

                Session s = (Session)session.get();

                if(s != null)

                {

                       s.close();

                       session.set(null);

                }

           }

}

在上面的代碼中,Hibernate Session被綁定到當前線程。當調用currentSession方法時,若是當前線程中的Session已經建立出來,那麼將返回這個已經存在的Session實例。

注意:幾乎全部狀況下,都不要使用每一個應用對應一次Hibernate Session的模式,也不要使用每次Http Session對應一次Hibernate Session的模式。

二、對於以上的狀況,Hibernate主要有以下3種模式來解決這個問題:

(1)自動版本化:Hibernate可以自動進行樂觀併發控制,若是在用戶思考的過程當中持久化實體發生併發修改,Hibernate可以自動檢測到。

(2)脫管現象:若是採用每次用戶請求對應一次Session的模式,那麼,前面載入的實例在用戶思考的過程當中,始終與Session脫離,處於脫管狀 態。Hibernate容許把脫管對象從新關聯到Session上,而且對修改進行持久化。在這種模式下,自動版本化被用來隔離併發修改。這種模式也被稱 爲脫管對象的每次請求對應一個Hibernate Session。

(3)長生命週期Session:Session能夠在數據庫事務提交以後,斷開和底層的JDBC鏈接。當新的客戶端請求到來時,它又從新鏈接上底層的 JDBC連接。這種模式被稱爲每一個應用程序事務對應一個Session。由於應用程序事務時至關長(跨越多個用戶請求)的,因此也被稱爲長生命週期 Session。

注意:Session緩存了處於持久化狀態的每一個對象(Hibernate會監視和檢查髒數據),也就是說,若是程序讓Session打開很長一段時間, 或者載入了不少數據,Session佔用的內存會一直增加,直到拋出OutOfMemoryException異常。爲了解決這個問題,程序按期調用 Session的clear()和evict()方法來管理Session的緩存。對於一些大批量的數據處理,推薦使用DML風格的HQL語句完成。

三、爲了保證在Session關閉以前初始化代理屬性或集合屬性,程序能夠Hibernate,initialized()靜態方法來強制初始化集合或代 理。只要Session處於open狀態,Hibernate.initialize(teahcer)將會強制初始化teacher代 理,Hibernate.initialize(teacher.getStudents())對student的集合具備一樣的功能。

還有另外一種選擇,就是程序讓Session一直處於打開狀態,直到裝入全部須要的集合或代理。

保證Session處於打開狀態有兩種方法能夠解決此問題:

(1)在一個Web應用中,能夠利用過濾器(Filter),在用戶請求結束、頁面生成結束時關閉Session。也就是保證在視圖層一直打開Session,這就是所謂的Open Session in View成視圖界面的過程當中發生異常時,必須保證能夠正確關閉Session,並結束事務。

(2)使用業務邏輯層來準備數據,在業務邏輯層返回數據以前,業務邏輯層對每一個所需集合調用Hibernate.initialize()方法,或者使用 帶fetch子句或FetchMethod.JOIN的查詢,事先取得全部數據,並將這些數據封裝成VO(值對象)集合,而後程序能夠關閉Session 了。業務邏輯層VO集傳入視圖層,讓視圖層只負責簡單的顯示邏輯。在這種模式下,可讓視圖層和Hibernate API完全分離,保證視圖層不會出現持久層API,從而提供更好的解耦。

 

 

十7、上下文相關的Session

從Hibernate3.1開始,SessionFactory.getCurrentSession()的底層實現是可插拔的,Hibernate引入 了CurrentSessionContext接口,並經過hibernate_current_session_context_class參數來管理 上下文相關Session的底層實現。

CurrentSessionContext接口有以下3個實現類:

org.hibernate.context.JTASessionContext:根據JTA來跟蹤和界定上下文相關Session,這和最先的僅支持JTA的方法是徹底同樣的。

org.hibernate.context.ThreadLocalSessionContext:經過當前正在執行的線程來跟蹤和界定上下文相關Session,也就是和前面的HibernateUtil的Session維護模式類似。

org.hibernate.context.ManagedSessionContext:經過當前執行的線程來跟蹤和界定上下文相關的 Session。可是程序須要使用這個類的靜態方法將Session實例綁定、取消綁定,它並不會自動打開、flush或者關閉任何Session。

對於容器中使用Hibernate的場景而言,一般會採用第一種方式:對於獨立的Hibernate應用而言,一般會採用第二種方式。

爲了指定Hibernate使用哪一種Session管理方式,能夠在hibernate.cfg.xml文件中增長以下片斷:

<property name="hibernate.current_session_context_class">thread</property>

若是在JTA事務環境中,則應增長以下配置片斷:

<property name="hibernate.current_session_context_class">jta</property>

對於第三種不經常使用的Session管理機制,則可在配置文件中簡寫成:managed。

 

http://blog.163.com/xiaokangzhijia@126/blog/#m=0&t=1&c=fks_084066087085082071086094081095085080084074081082094070082

相關文章
相關標籤/搜索