[英]In Hibernate Component tag lazy loading is not working
我有一個小的hibernate應用程序,如上所示:
BankAccount類如下:
package in.co.way2learn;
import java.util.Set;
public class BankAccount {
private int accountNumber;
private String accountHoldersName;
private int balance;
private Address address;
private Set<String> emails;
//setters and getters
}
地址類如下:
package in.co.way2learn;
public class Address {
private String addressLine1;
private String addressLine2;
private String city;
private String country;
private int pinCode;
//setters and getters
}
BankAccount.hbm.xml文件如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jul 2, 2014 3:59:34 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="in.co.way2learn">
<class name="BankAccount">
<id name="accountNumber" type="integer">
<generator class="assigned"/>
</id>
<property name="accountHoldersName" type="string"/>
<property name="balance" type="integer"/>
<component name="address" class="Address" lazy="true">
<property name="addressLine1"/>
<property name="addressLine2"/>
<property name="city"/>
<property name="country"/>
<property name="pinCode"/>
</component>
<set name="emails" order-by="email asc" table="bankaccount_emails">
<key column="SNo"/>
<element column="email" type="string"/>
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
org.gjt.mm.mysql.Driver
</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/way2learnDB
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="in/co/way2learn/BankAccount.hbm.xml"/>
</session-factory>
</hibernate-configuration>
現在我的問題是在我使用lazy =“true”的組件標簽中的BankAccount.hbm.xml
文件中,當我使用session.get(BankAccount.class, 1235);
在BankAccount類上觸發select查詢時session.get(BankAccount.class, 1235);
它也是從數據庫加載地址的詳細信息,我用來觸發選擇查詢的代碼如下:
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
BankAccount bankAccount=(BankAccount)session.get(BankAccount.class, 1235);
transaction.commit();
session.close();
觸發的查詢是
Hibernate:
select
bankaccoun0_.accountNumber as accountN1_0_0_,
bankaccoun0_.accountHoldersName as accountH2_0_0_,
bankaccoun0_.balance as balance3_0_0_,
bankaccoun0_.addressLine1 as addressL4_0_0_,
bankaccoun0_.addressLine2 as addressL5_0_0_,
bankaccoun0_.city as city6_0_0_,
bankaccoun0_.country as country7_0_0_,
bankaccoun0_.pinCode as pinCode8_0_0_
from
BankAccount bankaccoun0_
where
bankaccoun0_.accountNumber=?
但是我希望只使用bankAccount.getAddress()
方法時,地址詳細信息將從數據庫中bankAccount.getAddress()
加載?
現在任何人都可以解釋為什么hibernate急切地加載地址細節,以及如何加載懶惰?
以下代碼為例: -
class B {
private C cee;
public C getCee() {
return cee;
}
public void setCee(C cee) {
this.cee = cee;
}
}
class C {
// Not important really
}
在加載B之后,你可以調用getCee()
來獲得C.但是看看, getCee()
是你的類的一個方法,而Hibernate無法控制它。 Hibernate不知道有人打算調用getCee()
。 這意味着Hibernate必須在從數據庫加載B時將適當的值放入“ cee ”屬性。
如果為C啟用了代理,Hibernate可以放置一個尚未加載的C-proxy
對象,但是當有人使用它時將加載它。 這為一對一提供了延遲加載。
但現在想象你的B對象可能有也可能沒有關聯的C(約束=“假”) 。 當特定B沒有C時, getCee()
應該返回什么? 空值。 但請記住,Hibernate必須在設置B時設置正確的“cee”值(因為它不知道有人何時會調用getCee()
)。 代理在這里沒有幫助,因為代理本身已經是非null對象。
如果你的B-> C映射是強制性的(約束=真) ,Hibernate將使用C代理導致延遲初始化。 但是如果你允許B沒有C,那么Hibernate只是在它加載B時檢查C的存在。但是檢查存在的SELECT效率很低,因為相同的SELECT可能不僅僅檢查存在,而是加載整個對象。 懶惰的裝載消失了。
解決方法1 : - 只需在hdm文件中為@JoinColumn添加注釋或條目,以獲取引用的private Address address;
。
解決方法2 : - 在OneToOne
關系中添加optional = false
此問題的其他解決方案:
最簡單的就是偽造一對多的關系。 這將起作用,因為延遲加載集合比單個可空屬性的延遲加載容易得多,但是如果使用復雜的JPQL / HQL查詢,通常這種解決方案非常不方便。
另一種是使用構建時間字節碼檢測。 有關更多詳細信息,請閱讀Hibernate文檔:19.1.7。 使用lazy屬性獲取。 請記住,在這種情況下,您必須將@LazyToOne(LazyToOneOption.NO_PROXY)
注釋添加到一對一關系中以使其變得懶惰。 將提取設置為LAZY是不夠的。
最后一個解決方案是使用運行時字節碼檢測,但它只適用於那些在完整的Java EE環境中使用Hibernate作為JPA提供者的人(在這種情況下,將“ hibernate.ejb.use_class_enhancer
”設置為true應該可以做到這一點:實體管理器配置)或使用配置了Spring的Hibernate進行運行時編織(這在某些較舊的應用程序服務器上可能很難實現)。 在這種情況下,還需要@LazyToOne(LazyToOneOption.NO_PROXY)
注釋。
這對你有用。
Hibernate不會為組件創建代理,這就是為什么延遲加載對它們不起作用的原因。
解決方案:
BankAccount
使用兩個不同的類,一個包含Address
組件(現在是),一個沒有它,並將它們映射到同一個表。 然后,在不需要地址的上下文中使用沒有地址的那個。 Address
組件作為實體並將其映射到同一個表,在BankAccount
和Address
之間使用假的一對一關聯。 這里的缺點是您不能插入Address
實例(因為您最終會嘗試在表中插入單獨的行),而是在插入相應的BankAccount
實體實例后必須讀取並更新它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.