1. 程式人生 > >【hibernate】Hibernate中get()和load()的區別

【hibernate】Hibernate中get()和load()的區別

etime () bsp ava fin null void 自己 IT

Hibernate中根據Id單條查詢獲取對象的方式有兩種,分別是get()和load(),來看一下這兩種方式的區別。

1. get()

使用get()來根據ID進行單條查詢:

1 User user=session.get(User.class, "1");

當get()方法被調用的時候就會立即發出SQL語句:

1 2 3 4 5 6 7 8 9 10 11 Hibernate: select user0_.ID as ID1_1_0_, user0_.CREATETIME as CREATETI2_1_0_,
user0_.UPDATETIME as UPDATETI3_1_0_, user0_.USERNAME as USERNAME4_1_0_, user0_.PASSWD as PASSWD5_1_0_ from USER user0_ where user0_.ID=?

並且返回的對象也是實際的對象:

技術分享圖片

使用get()和普通的單條查詢並沒有多大的區別。

2. load()

當使用load()進行查詢的時候情況就變得很不一樣了:

1 User user=session.load(User.
class, "1");

當調用load()方法的時候會返回一個目標對象的代理對象,在這個代理對象中只存儲了目標對象的ID值,只有當調用除ID值以外的屬性值的時候才會發出SQL查詢的。

返回值:

技術分享圖片

在handler中有一個屬性叫做target,保存著被代理的對象:

技術分享圖片

現在這個位置還是空的呢。

當我們嘗試下面的代碼時:

1 2 User user=session.load(User.class, "1"); System.out.println(user.getId());

因為我們只訪問了ID屬性,這個在代理對象中是已經存在的了,所以並不需要再去數據庫中查詢,因此並不會發出SQL查詢語句。

當使用到除ID以外的屬性的時候,會發出SQL查詢語句,比如嘗試執行下面的代碼:

1 2 User user=session.load(User.class, "1"); System.out.println(user.getUsername());

會發現控制臺打印了SQL查詢語句:

1 2 3 4 5 6 7 8 9 10 11 Hibernate: select user0_.ID as ID1_1_0_, user0_.CREATETIME as CREATETI2_1_0_, user0_.UPDATETIME as UPDATETI3_1_0_, user0_.USERNAME as USERNAME4_1_0_, user0_.PASSWD as PASSWD5_1_0_ from USER user0_ where user0_.ID=?

這個時候再看代理對象的話,會發現target已經被填充上了:

技術分享圖片

3. Exception

下面的代碼會報一個空指針異常:

1 2 User user=session.get(User.class, "foobar"); System.out.println(user.getUsername());

上面的這段代碼拋出了空指針異常 NPE:

技術分享圖片

這個是很容易理解的,因為沒有查詢到的就空指針了嘛。

而下面的這段代碼則會報一個ObjectNotFoundException異常:

1 2 User user=session.load(User.class, "foobar"); System.out.println(user.getUsername());

拋出了ObjectNotFoundException異常:

技術分享圖片

這個就有點奇怪了,這個是因為我們使用load()的時候返回的是一個代理對象,因為這個時候還沒有進行查詢,所以我們並沒有辦法確定要查詢的對象到底存在不存在,所以使用load()查詢的返回值是永遠不會為空的,但是呢,當我們試圖訪問被代理的真實對象的時候,因為這個對象並不存在,所以就拋出了一個ObjectNotFoundException。

還有一種說法是get()是用於不確定對象是否真的存在的情況,所以在查詢出來後可以先進行一個空指針判斷,而load()方法用於對象一定存在的情況下,不然等會兒使用的時候就可能會拋出ObjectNotFoundException了。

再來看下面這段代碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Test public void test_001(){ SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory(); Session session=sessionFactory.openSession(); User user=null; try { session.beginTransaction(); user=session.load(User.class, "foobar"); session.getTransaction().commit(); } catch (Exception e) { session.getTransaction().rollback(); e.printStackTrace(); }finally{ try { session.close(); } catch (Exception e) { e.printStackTrace(); } } System.out.println(user.getUsername()); }

拋出了一個LazyInitializationException:

技術分享圖片

這個是因為我們使用load()查詢出來的對象只有在調用完非ID屬性的時候才會去查詢數據填充進來,但是查詢數據的時候是需要依賴產生這個代理對象的那個Session去查詢的,當我們將Session關閉後,再試圖去訪問非ID屬性,它正打算拿著自己依賴的Session去數據庫查詢,一看Session竟然被關閉了,得,幹脆拋出一個LazyInitializationException好了。

解決辦法就是在查詢的時候思考一下,這個對象時候需要在Session關閉之後還能使用得到呢?如果是的話,那麽我們使用get()來查詢,或者手動調用空訪問一個非ID屬性讓它把數據回填上先。

4. 緩存

get()和load()都會使用緩存,都是首先從一級緩存Session中查找,當找不到的時候再去二級緩存中查找,當查詢不到的時候get()返回的是null,而load()則返回代理對象。

來看下面這段代碼:

1 2 User user1=session.get(User.class, "1"); User user2=session.load(User.class, "1");

來看一下這兩條執行過後這兩個變量的值:

技術分享圖片

會發現兩個都是真實對象,連load()返回的也是真實對象,並且它們引用的還是同一塊對象。

這個是因為get()查詢出來ID為1的對象後會將其放入到緩存中,而load()再去查詢的時候它會先去緩存中查找,如果緩存中沒有的話才會返回代理對象,但是當緩存中已經存在的話就直接將真實對象返回來了。

5. 對比總結

返回值:

get()返回的是查詢出來的實體對象,而load()查詢出來的是一個目標實體的代理對象。

查詢時機:

get()在調用的時候就立即發出SQL語句查詢,而load()在訪問非ID屬性的時候才會發出查詢語句並且將被代理對象target填充上,但是如果這個動作發生在Session被關閉後的話就會拋出LazyInitializationException。

查詢結果為空時:

get()拋出NullPointerException

load()拋出ObjectNotFoundException

轉載:https://www.cnblogs.com/cc11001100/p/6883790.html

【hibernate】Hibernate中get()和load()的區別