hibernate註解(三)

來源:互聯網
上載者:User

我們繼續介紹hibernate註解的相關內容

1. OneToOne懶載入問題

一對一註解時,若採用外鍵列進行實體的關聯的話,懶載入問題是需要注意下的。如下:

Student表:

id  int  not nullname  varchar(50)  not nullcard_id  int  not null

Card表:

id  int  not nullcard_no  varchar()  not null

Student類

public class Student {private int id;private String name;private Card card;....@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)@JoinColumn(name = "card_id")public Card getCard() {return card;}public void setCard(Card card) {this.card = card;}}

Card類

public class Card {private int id;private String cardNo;private Student student;....@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "card")public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}}

 按照上述關係,運行代碼後我們會發現,Student擷取Card時可以懶載入,但Card擷取Student時卻無法懶載入,那麼這是為什麼呢?

原因:在Card表裡由於沒有關係欄位,因此僅從Card表角度看無法知道擁有該卡的學生是誰(除非在Card表建立Student表的外鍵student_id,但由於冗餘了關係欄位,因此很少有人這麼幹吧【注意sql的join語句是考慮了兩張表的】),而從Student角度不一樣,由於含有card_id欄位可能清楚知道該學生擁有一張卡。

正是由於上面的原因,因此當從Card擷取Student時,hibernate為了確定Student表中到底有沒有該Card,因此發了一條sql:select * from Student where card_id = ?,參數既是該Card的id,以此來維護Card與Student的關係。

還有一種解釋,但需要理解hibernate的懶載入的機制:代理。

2. 懶載入原理

hibernate使用了代理(Proxy),對實體的調用會被代理接受和處理,hibernate可以設定這個代理被調用到的時候去載入資料,從而實現消極式載入。那麼對於一個映射對象,要麼它有值,要麼它是null,對於null值建立代理是沒多大作用的,而且也不能對null建立動態代理。那就是說hibernate在對消極式載入建立代理的時候要考慮這個映射的對象是否是null。如果是null不需要建立代理,直接把映射的值設定成null,如果映射的對象不為null,那麼hibernate就建立代理對象。

簡而言之,為null就不能懶載入,為代理對象才能懶載入。

 

那麼解決上述問題的辦法呢?

● Card類的getStudent改為manyToOne,並設定unique=true。缺點:需要將欄位改為Set<Student>。

● 手動為Student建立代理對象。(不建議這麼做,而且我也沒試過)

● 採用no-proxy懶載入機制,對類用instrument進行增強,即用類增強器對二進位Class檔案進行強化處理。(很少有人這麼做,不推薦)

以下是利用ant調用hibernate類增強器對class檔案進行強化處理,ant的build.xml指令碼如下:

<?xml version="1.0" encoding="UTF-8"?><project name="hibernatelazy" default="instrument" basedir=".">       <property name="lib.dir" value="./lib"/>       <property name="classes.dir" value="./classes"/>       <path id="lib.class.path">             <fileset dir="${lib.dir}">                    <include name="**/*.jar"/>              </fileset>        </path>        <target name="instrument">            <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">                     <classpath path="${classes.dir}"/>                     <classpath refid="lib.class.path"/>             </taskdef>             <instrument verbose="true">                      <fileset dir="${classes.dir}/com/derek/known/hbm">                            <include name="Knownquestions.class"/>                      </fileset>              </instrument>         </target></project>

其中注意:

<property name="lib.dir" value="./lib"/>所需的JAR檔案路徑。

<property name="classes.dir" value="./classes"/>編譯輸出路徑。

我把build.xml放在了WEB-INF目錄下,輸出路徑就設定為該目錄下的classes目錄,待增強位元組碼檔案為classes目錄下的com/derek/known/hbm/Knownquestions.class; 在命令列下切換到此目錄,執行ant命令,即產生新的Knownquestions.class。

● 放棄懶載入,改為join的載入策略,或者使用hql:from Card t inner join fetch t.student r

3. 懶載入註解方式詳解

● FetchType(@OneToOne、@OneToMany等註解裡的fetch屬性對應的類,本身沒有註解)

JPA標準的通用載入策略註解屬性。FetchType可選值意義與區別如下:

FetchType.LAZY:懶載入,在第一次訪問關聯對象的時候載入

FetchType.EAGER:立刻載入,在查詢主對象的時候同時載入關聯對象。

● @Fetch

hibernate定義了載入關聯關係的擷取策略。Fetch可選值意義與區別如下:

FetchMode.JOIN:始終立刻載入,使用外連(outer join)查詢的同時載入關聯對象,忽略FetchType.LAZY設定。

FetchMode.SELECT:支援懶載入(除非設定關聯屬性lazy=false),當訪問每一個關聯對象時載入該對象,會累計產生N+1條sql語句

FetchMode.SUBSELECT:支援懶載入(除非設定關聯屬性lazy=false),在訪問第一個關聯對象時載入所有的關聯對象。會累計產生兩條sql語句。

● @LazyToOne

hibernate定義了@ManyToOne 和@OneToOne 關聯的延遲選項。LazyToOne可選值意義與區別如下:

LazyToOneOption.PROXY:基於代理的消極式載入。

LazyToOneOption.NO_PROXY:基於位元組碼增強消極式載入 - 注意需要在構建期處理位元組碼增強。

LazyToOneOption.FALSE:非消極式載入的關聯。

● @LazyCollection

hibernate定義了@ManyToMany和@OneToMany 關聯的延遲選項。LazyCollection可選值意義與區別如下:

LazyCollectionOption.TRUE:集合具有延遲性,只有在訪問的時候才載入。

LazyCollectionOption.EXTRA:集合具有延遲性,並且所有的操作都會盡量避免載入集合, 對於一個巨大的集合特別有用,因為這樣的集合中的元素沒有必要全部載入。

LazyCollectionOption.FALSE:非消極式載入的關聯。

 

延遲和擷取選項的等效註解

Annotations

Lazy

Fetch

@[One|Many]ToOne](fetch=FetchType.LAZY)

@LazyToOne(PROXY)

@Fetch(SELECT)

@[One|Many]ToOne](fetch=FetchType.EAGER)

@LazyToOne(FALSE)

@Fetch(JOIN)

@ManyTo[One|Many](fetch=FetchType.LAZY)

@LazyCollection(TRUE)

@Fetch(SELECT)

@ManyTo[One|Many](fetch=FetchType.EAGER)

@LazyCollection(FALSE)

@Fetch(JOIN)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.