摘要:非集合屬性非集合屬性的延遲加載相對比較復雜。僅通過注解是無法實現延遲加載的。但是在一對一關系中,延遲加載是有陷阱的。這樣一來,就會立即為配置延遲加載的實體生成一個動態代理類。
Hibernate中,延遲加載針對屬性類別可以分為兩類,一類是延遲屬性加載,另一類是延遲關聯實體加載。
屬性延遲加載屬性有可以分為兩種類型:一種是集合屬性,一種是非集合屬性(如String、Integer……)。
集合屬性集合屬性的延遲加載通過PersistentSet、 PersistentList、PersistentBag、PersistentMap、PersistentSortedMap、PersistentSortedSet作為代理類來實現,代理類中保存了session以及owner屬性,owner屬性表示了集合屬性所屬的one側的實體。
非集合屬性非集合屬性的延遲加載相對比較復雜。僅通過@Basic(fetch = FetchType.LAZY)注解是無法實現延遲加載的。需要讓實體實現FieldHandled接口,聲明FieldHandler屬性,通過攔截器原理注入對應的FieldHandler屬性,起到類似于上述代理類的作用,FieldHandler同樣也保持了session,以及需要延遲加載的屬性。下面的代碼實現了非集合屬性的延遲加載
@Basic(fetch = FetchType.LAZY) @Column(name="CONTENT") public String getContent() { if (fieldHandler != null) { return (byte[]) fieldHandler.readObject(this, "content", content); } return null; } public void setContent(byte[] content) { this.content = content; } @Override public void setFieldHandler(FieldHandler handler) { this.fieldHandler = handler; } @Override public FieldHandler getFieldHandler() { return this.fieldHandler; }
Hibernate官網對非結合屬性的延遲加載有如下的評論:
Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.
A different way of avoiding unnecessary column reads, at least for read-only transactions, is to use the projection features of HQL or Criteria queries. This avoids the need for buildtime bytecode processing and is certainly a preferred solution.
大致的意思就是:應該是因為,我們并未用到編譯時字節碼增強技術的原因。如果只對部分property進行延遲加載的話,hibernate還提供了另外的方式,也是更為推薦的方式,即HQL或者條件查詢。
更為推薦的方式說白了就是在查詢的時候就過濾掉不需要的屬性,以下列出HQL和Criterial的兩種實現方法:
// criterial實現 criteria.setProjection( Projections.projectionList().add(Projections.property("id"), "id") .add(Projections.property("age"), "age")).setResultTransformer( Transformers.aliasToBean(User.class)); // HQL實現 Query query = session.createQuery("select u.id as id,u.age as age from User u where u.id=2"); query.setResultTransformer(Transformers.aliasToBean(User.class));關聯實體延遲加載
關聯實體延遲加載分兩種情況,一種是多對一,另一種是一對一。
多對一關聯關聯實體是多個實體時(包括一對多、多對多):此時關聯實體將以集合的形式存在,Hibernate 將使用 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合來管理延遲加載的實體。這就是前面所介紹的情形。
一對一關聯關聯實體是單個實體時(包括一對一、多對一):當 Hibernate 加載某個實體時,延遲的關聯實體將是一個動態生成代理對象。Hibernate 使用 Javassist 項目動態生成的代理類——當 Hibernate 延遲加載關聯實體時,將會采用 Javassist 生成一個動態代理對象,這個代理對象將負責代理“暫未加載”的關聯實體。但是在一對一關系中,延遲加載是有陷阱的。一對一關聯一般有兩種形式,一種是主鍵關聯;另一種是外鍵關聯。
主鍵關聯數據表Husband,兩列屬性id,name
數據表Wife,兩列屬性id,name
Husband實體: @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false) @PrimaryKeyJoinColumn getWife() @GenericGenerator(name = "Wife", strategy = "foreign", parameters = { @Parameter(name = "property", value = "husband") }) Wife實體: @OneToOne(mappedBy = "wife", fetch = FetchType.LAZY) getHusband()
以上是hibernate中的配置。其中“optional=false”的配置時關鍵,否則即使配置了fetch策略為lazy,也無法做到在獲取husband實體的時候延遲加載wife實體。optional的默認值是true,表示關聯的實體可以為null。在一對一的延遲加載中,hibernate并非一定對需要延遲加載的實體生成一個動態代理對象,而是當被關聯的實體確定不為null時,才會生成,否則直接將其置為null。所以問題就來了,對于兩個通過主鍵關聯的一對一實體,在獲取到其中一個實體后,要判斷與之關聯的實體是否存在,則必須要再查詢一次數據庫才可以。這也就是為什么在設置了延遲加載策略后,hibernate還是立即發送了一次查詢請求給數據庫。
要解決一對一關系中的延遲加載,共有兩種方法:一種就是上面提到的,把optional設置為false,即關聯的實體一定不為null。這樣一來,hibernate就會立即為配置延遲加載的實體生成一個動態代理類。
但是這又存在一個坑,在創建實體husband的時候,其主鍵為null(還未生成),wife的主鍵也為null,此時save的話,hibernate理論上應該先insert husband實體,然后用生成出來的husband_id作為wife的主鍵進行insert。可事與愿違,hibernate認為此情況違背了optional=false的假設,故會拋異常IdentifierGenerationException,即wife的id為null。具體原因不太知曉,猜測可能是因為持久化的順序,先持久化husband,此時wife的主鍵為null,但是你又配置了optional=false,故前后矛盾而拋出異常。
數據表Husband,3列屬性id,name, wife_id
數據表Wife,兩列屬性id,name
其中husband_id與Husbande中的id關聯
Husband實體: @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "wife_id", , referencedColumnName = "id") getWife() Wife實體: @OneToOne(mappedBy = "wife", fetch = FetchType.LAZY) getHusband()
這樣一來,直接可以通過husband中的wife_id的null與否來判斷wife實體是否為null。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64770.html
摘要:項目使用的版本進行開發,里面使用到,而這個版本自帶的實現是的版本。這個版本里面的延遲加載是沒有問題的,當你設置時,關聯的對象在你沒有使用的時候,是不會發出的。這個問題,在升級版本后是解決了的。 項目使用springboot的1.5.19版本進行開發,里面使用到JPA,而springboot這個版本自帶的JPA實現是Hibernate的5.0.12版本。 這個版本里面的延遲加載是沒有問題...
摘要:本文首發于的博客轉載請注明出處邏輯分頁和物理分頁的區別是什么分頁是為了節省網絡傳輸的數據量邏輯分頁是將數據全部加載到內存,再通過后端邏輯控制分頁顯示到前端物理分頁是在數據庫層面分部分獲取數據,通常情況下對內存的壓力較邏輯分頁少是否支持延遲加 ????本文首發于cartoon的博客????轉載請注明出處:https://cartoonyu.github.io/c... Mybatis...
摘要:中怎樣實現類之間的關系如一對多多對多的關系中怎樣實現類之間的關系如一對多多對多的關系它們通過配置文件中的來實現類之間的關聯關系的。 Hibernate常見面試題 Hibernate工作原理及為什么要用? Hibernate工作原理及為什么要用? 讀取并解析配置文件 讀取并解析映射信息,創建SessionFactory 打開Sesssion 創建事務Transation 持久化操作 提...
摘要:查詢照樣寫就行,如下參考問題七中關于多表連接查詢和返回值集合中對象問題錯誤的查詢語句釋放分析原來是查詢出來的字段并不能自動轉換為對象。參考問題八原因原生的語句中返回值為,而語句中的返回值位型的,網上說的主要是兼容而做的。 首先奉上Hibernate3.2 API地址:http://docs.jboss.org/hiberna...Hibernate4.3 API地址:http://do...
摘要:執行沒有,批處理不支持,將所有都添加到批處理中,等待統一執行,它緩存了多個對象,每個對象都是完畢后,等待逐一執行批處理。 Mybatis常見面試題 #{}和${}的區別是什么? #{}和${}的區別是什么? 在Mybatis中,有兩種占位符 #{}解析傳遞進來的參數數據 ${}對傳遞進來的參數原樣拼接在SQL中 #{}是預編譯處理,${}是字符串替換。 使用#{}可以有效的防止...
閱讀 1222·2023-04-26 00:47
閱讀 3575·2021-11-16 11:53
閱讀 801·2021-10-08 10:05
閱讀 2746·2021-09-22 15:19
閱讀 2985·2019-08-30 15:55
閱讀 2760·2019-08-29 16:55
閱讀 2928·2019-08-29 15:20
閱讀 1116·2019-08-23 16:13