為了進一步優化Hibernate的性能可以使用
延遲加載技術管理數據抓取策略進行緩存管理 等方面考慮來提高Hibernate的性能
延遲加載(load)
延遲加載(load)是Hibernate為提高程序執行效率而提供的一種機制即只有真正使用該對象的數據時才會創建
延遲加載的過程通過代理(Proxy)機制來實現延遲加載Hibernate從數據庫獲取某一個對象數據時獲取某一個對象的集合屬性值時或獲取某一個對象所關聯的另一個對象時由於沒有使用該對象的數據(除標識符外)Hibernate並不從數據庫加載真正的數據而只是為該對象創建一個代理對象來代表這個對象這個對象上的所有屬性都為默認值只有在真正需要使用該對象的數據時才創建這個真正的對象真正從數據庫中加載它的數據
當調用Session上的load()方法加載一個實體時當Session加載某個實體時會對這個實體中的集合屬性值采用延遲加載當Session加載某個實體時會對這個實體所單端關聯的另一個實體對象采用延遲加載
關閉延遲加載在加載單個實體時可以使用get()方法
對於實體中的集合屬性可以在這個集合的(<set><bag><list>…)添加屬性lazy=false單端關聯另一個實體對象時可以在映射文件中配置<onetoone><manytoone> 添加屬性lazy=false注意onetoone不能有constrained=true(產生的sql語句中顯示外鍵)否則懶加載不起作用
Hibernate中默認采用延遲加載的情況主要有以下幾種
? 當調用Session上的load()方法加載一個實體時會采用延遲加載
? 當Session加載某個實體時會對這個實體中的集合屬性值采用延遲加載(onetomany)
? 當Session加載某個實體時會對這個實體所單端關聯(onetoone manytoone)的另一個實體對象采用延遲加載
? 第二種和第三種的區別是第二種情況下取消延時加載的方法是在單方即有set屬性的一方的映射文件的set標簽後設置懶加載的屬性lazy=false;第三種情況則是在多方即有manytoone的一方的映射文件中的manytoone標簽後設置lazy=false
能夠懶加載的對象都是被改寫過的代理對象當相關聯的session沒有關閉時訪問這些懶加載對象(代理對象)的屬性(getId和getClass除外)hibernate會初始化這些代理或用Hibernateinitialize(proxy)來初始化代理對象當相關聯的session關閉後再訪問懶加載的對象將出現異常
抓取策略(fetch)
通過配置抓取策略來直接影響session的get()和load()方法的查詢效果
單端關聯<manytoone><oneto_one>上的抓取策略
可以給單端關聯的映射元素添加fetch屬性select:延遲加載 join:在同一條select語句使用內連接來獲得對象的數據和它關聯對象的數據此時關聯對象的延遲加載失效
集合屬性上的抓取策略
select:延遲加載join:在同一條select語句使用內連接來獲得對方的關聯集合此時關聯集合上的lazy會失效subselect:另外發送一條查詢語句或子查詢抓取這個策略對HQL的查詢也起作用
延遲加載案例分析
情況一單個實體調用load()方法取消懶加載
[java]
package comhbsitest;
import orghibernateSession;
import orgjunitTest;
import comhbsidomainUser;
import comhbsiutilsHibernateUtil;
publicclass TestLazy {
//測試get()方法get()方法不管你有沒有用到總會執行sql語句
@Test
publicvoid testGet(){
Session session = HibernateUtilgetSession()
User user = (User) sessionget(Userclass)
// Systemoutprintln(usergetName())
HibernateUtilclose()
//這裡要注意的是即使關閉了session使user處於托管狀態仍然可以可以使用user對象這是因為雖然處於托管狀態但是這個對象是存在屬性值的對象並沒有把他刪除只是隔絕了它與數據庫的打交道的通道
Systemoutprintln(usergetName())
}
//測試load()方法不執行sql語句用到的時候才執行
@Test
publicvoid testLoad(){
Session session = HibernateUtilgetSession()
User user = (User) sessionload(Userclass)
//這裡輸出id也不會執行sql語句直接從上面你傳進去的id中獲取id沒有從數據庫中查找所以也不執行sql語句
Systemoutprintln(usergetId())
//而輸出name就不一樣了這時其實就是實例化了代理對象這是的代理對象有了name的屬性這時即使你關閉了session也可以通過這個對象獲取到name;如果注釋這句即不實例化代理對象又在關閉session後執行輸出name屬性這時會報錯could not initialize proxy
// Systemoutprintln(usergetName())
HibernateUtilclose()
Systemoutprintln(usergetName())
}
}
情況二set集合上取消懶加載
//測試如果在映射文件中將集合屬性中的懶加載設置為false後將連帶著orders表中數據一塊提出來即兩條select語句
[java]
@Test
publicvoid find(){
Session session = HibernateUtilgetSession()
Customer cus = (Customer) sessionget(Customerclass)
Systemoutprintln(cusgetCname())
//用到下面這種方法輸出會出現兩天sql語句而且是分開的如果用到懶加載會出現先輸出兩條sql語句在輸出結果
//這裡不能直接方法鏈式輸出cusgetOrd()getOname()因為cusgetOrd()返回的是一個set集合
Set<Orders> orders = cusgetOrd()
Systemerrprintln(orderssize())
HibernateUtilclose()
}
方法三<onetoone><manytoone> 取消懶加載
[java]
@Test
publicvoid find(){
//默認使用懶加載即用著一條sql語句就輸出一條如果設置延時加載為false後輸出兩條sql語句將不需要的顧客信息也查出來
Session session = HibernateUtilgetSession()
Orders ord = (Orders) sessionget(Ordersclass)
Systemoutprintln(ordgetOname())
HibernateUtilclose()
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28447.html