-- 翻譯自https://www.mkyong.com/hibernate/different-between-session-get-and-session-load/
很多時候你會發現,使用Hibernate的開發人員會混淆session.get()和session.load()的用法,你是否理解這兩個方法的區別並知道在什么時候使用正確的方法呢?
實際上,兩個方法都是用來從數據庫獲取對象,只不過實現機制不一樣而已。
1. session.load()
- 這種方式總是會返回一個代理而不是真正得去查詢數據庫。 在Hibernate里面,代理是一個依據ID值獲取到的對象,該對象的屬性還沒有初始化,它看起來就是一個臨時的虛擬對象而已。
- 如果load方法沒有找到數據,就會拋出ObjectNotFoundException.
2. session.get()
- 這種方式總是會去數據庫查詢數據並返回一個真實的對象,該對象就代表數據庫中的一行而非代理。
- 如果沒有找到數據就會返回null.
性能方面的區別
由於某些原因,Hibernate會創建一些對象,當你做關聯查詢的時候,為了維護對象之間的關系,一般來說你會從數據庫中拿到一個對象(持久化的實例)並把該對象作為一個引用指向另一個對象。我們來看一個例子來讓大家理解什么情況下我們應該使用session.load().
1. session.get()
拿一個股票的應用來說,股票跟股票交易之間應該是一對多的關系,當你保存一次股票交易的時候,一般來說我們會寫如下的代碼:
Stock stock = (Stock)session.get(Stock.class, new Integer(2)); StockTransaction stockTransactions = new StockTransaction(); //set stockTransactions detail stockTransactions.setStock(stock); session.save(stockTransactions);
輸出:
Hibernate: select ... from mkyong.stock stock0_ where stock0_.STOCK_ID=? Hibernate: insert into mkyong.stock_transaction (...) values (?, ?, ?, ?, ?, ?)
用session.get(), Hibernate會查詢數據庫以獲取Stock對象,並把該對象作為一個引用指向StockTransaction對象。然而,保存流程數據的操作是很耗費資源的,如果一個小時內有成千上萬次股票交易,你認為有必要每次都去查詢數據庫,去首先拿到Stock的真實對象然后把StockTransaction保存到數據庫中嗎?畢竟來說,你只是需要一個Stock的對象來讓StockTransaction引用而已。
2. session.load()
在上面的應用場景中,session.load()會是一個好的解決方案,讓我們來看一個例子:
Stock stock = (Stock)session.load(Stock.class, new Integer(2)); StockTransaction stockTransactions = new StockTransaction(); //set stockTransactions detail stockTransactions.setStock(stock); session.save(stockTransactions);
輸出:
Hibernate: insert into mkyong.stock_transaction (...) values (?, ?, ?, ?, ?, ?)
使用session.load()方式,Hibernate不會查詢數據庫(輸出的SQL里面沒有select語句)來獲取Stock對象,這種方式會返回一個Stock的代理對象 - 一個依據給定的ID值得虛假對象。這這種場景中,一個代理對象就足夠用來保存股票交易的記錄了。
異常方面的區別
session.load()
Stock stock = (Stock)session.load(Stock.class, new Integer(100)); //proxy //initialize proxy, no row for id 100, throw ObjectNotFoundException System.out.println(stock.getStockCode());
load方法總是會依據給定的ID值來返回一個代理對象,哪怕這個ID值甚至都不存在於數據庫。然而,當Hibernate試圖從數據庫中獲取屬性來初始化該代理對象的時候,它就會使用select語句來從數據庫查詢數據,如果沒有找到任何數據行,就會拋出ObjectNotFoundException了
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.mkyong.common.Stock#100]
session.get()
//return null if not found Stock stock = (Stock)session.get(Stock.class, new Integer(100)); System.out.println(stock.getStockCode()); //java.lang.NullPointerException
與load方法不一樣,如果在數據庫中沒有找到數據,get方法會返回null.
總結:
關於這兩個方法的選擇沒有一成不變的解決方案,你必須要首先理解這兩種方法的區別和聯系,然后才能決定哪種方式更適合你的應用場景。
PS:第一次翻譯國外網站的文章,感覺真是費力,本人英語水平有限,還請各位多多諒解。其實關於session.get()和session.load()的區別,只要記住兩點就好了:
1. load方法支持延遲加載而get方法則不會。
2. load方法在沒找到數據的時候會拋出ObjectNotFoundException而get方法則會返回空
