Hibernate框架中get和load查詢

来源:https://www.cnblogs.com/yiidian/archive/2020/04/05/12638397.html
-Advertisement-
Play Games

原文鏈接:http://www.yiidian.com/hibernate/hibernate get load.html 1 演示get和load方法的基本使用 源碼下載:https://pan.baidu.com/s/1c2HD7tm 2 分析get和load方法的區別 在hibernate中我 ...


原文鏈接:http://www.yiidian.com/hibernate/hibernate-get-load.html

1 演示get和load方法的基本使用

/**
 * 演示基本對象的查詢
 * @author http://www.yiidian.com
 *
 */
public class Demo {

	/**
	 * get()方法: 查詢一個對象
	 */
	@Test
	public void test1(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		Customer cust = session.get(Customer.class,1);
		Set<Order> orders = cust.getOrders();
		System.out.println(cust.getName()+"的訂單:");
		for (Order order : orders) {
			System.out.println(order.getOrderno());
		}
		
		tx.commit();
		session.close();
	}
	
	/**
	 * load()方法: 查詢一個對象
	 */
	@Test
	public void test2(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		Customer cust = session.load(Customer.class,1);
		Set<Order> orders = cust.getOrders();
		System.out.println(cust.getName()+"的訂單:");
		for (Order order : orders) {
			System.out.println(order.getOrderno());
		}
		
		tx.commit();
		session.close();
	}
}

源碼下載:https://pan.baidu.com/s/1c2HD7tm

2 分析get和load方法的區別

在hibernate中我們知道如果要從資料庫中得到一個對象,通常有兩種方式,一種是通過session.get()方法,另一種就是通過session.load()方法,然後其實這兩種方法在獲得一個實體對象時是有區別的,在查詢性能上兩者是不同的。

2.1 load載入方式

當使用load方法來得到一個對象時,此時hibernate會使用延遲載入的機制來載入這個對象,即:當我們使用session.load()方法來載入一個對象時,此時並不會發出sql語句,當前得到的這個對象其實是一個代理對象,這個代理對象只保存了實體對象的id值,只有當我們要使用這個對象,得到其它屬性時,這個時候才會發出sql語句,從資料庫中去查詢我們的對象。   

session = HibernateUtil.openSession();
/*
 * 通過load的方式載入對象時,會使用延遲載入機制,此時並不會發出sql語句,只有當我們需要使用的時候才會從資料庫中去查詢
*/
User user = (User)session.load(User.class, 2);

我們看到,如果我們僅僅是通過load來載入我們的User對象,此時從控制台我們會發現並不會從資料庫中查詢出該對象,即並不會發出sql語句,但如果我們要使用該對象時:   

session = HibernateUtil.openSession();
User user = (User)session.load(User.class, 2);
System.out.println(user);

此時我們看到控制台會發出了sql查詢語句,會將該對象從資料庫中查詢出來:

Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
User [id=2, username=aaa, password=111, born=2013-10-16 00:14:24.0]

這個時候我們可能會想,那麼既然調用load方法時,並不會發出sql語句去從資料庫中查出該對象,那麼這個User對象到底是個什麼對象呢?

其實這個User對象是我們的一個代理對象,這個代理對象僅僅保存了id這個屬性:   

session = HibernateUtil.openSession();
/*
* 通過load的方式載入對象時,會使用延遲載入機制,此時得到的User對象其實是一個
* 代理對象,該代理對象裡面僅僅只有id這個屬性
*/
User user = (User)session.load(User.class, 2);
System.out.println(user.getId());

我們看到,如果我們只列印出這個user對象的id值時,此時控制台會列印出該id值,但是同樣不會發出sql語句去從資料庫中去查詢。這就印證了我們的這個user對象僅僅是一個保存了id的代理對象,但如果我需要列印出user對象的其他屬性值時,這個時候會不會發出sql語句呢?答案是肯定的:

session = HibernateUtil.openSession();
/*
* 通過load的方式載入對象時,會使用延遲載入機制,此時得到的User對象其實是一個
* 代理對象,該代理對象裡面僅僅只有id這個屬性
*/
User user = (User)session.load(User.class, 2);
System.out.println(user.getId());
// 如果此時要得到user其他屬性,則會從資料庫中查詢
System.out.println(user.getUsername());   

此時我們看控制台的輸出:

2
Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
aaa

相信通過上述的幾個例子,大家應該很好的瞭解了load的這種載入對象的方式了吧。

2.2 get載入方式

相對於load的延遲載入方式,get就直接的多,當我們使用session.get()方法來得到一個對象時,不管我們使不使用這個對象,此時都會發出sql語句去從資料庫中查詢出來: 

session = HibernateUtil.openSession();
/*
* 通過get方法來載入對象時,不管使不使用該對象,都會發出sql語句,從資料庫中查詢
*/
User user = (User)session.get(User.class, 2);

此時我們通過get方式來得到user對象,但是我們並沒有使用它,但是我們發現控制台會輸出sql的查詢語句:

Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?

因此我們可以看到,使用load的載入方式比get的載入方式性能要好一些,因為load載入時,得到的只是一個代理對象,當真正需要使用這個對象時再去從資料庫中查詢。

2.3 使用get和load時的小問題

當瞭解了load和get的載入機制以後,我們此時來看看這兩種方式會出現的一些小問題:

①如果使用get方式來載入對象,當我們試圖得到一個id不存在的對象時,此時會報NullPointException的異常

session = HibernateUtil.openSession();
/*
* 當通過get方式試圖得到一個id不存在的user對象時,此時會報NullPointException異常
*/
User user = (User)session.get(User.class, 20);
System.out.println(user.getUsername());

此時我們看控制台的輸出信息,會報空指針的異常:

Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
java.lang.NullPointerException  .........

這是因為通過get方式我們會去資料庫中查詢出該對象,但是這個id值不存在,所以此時user對象是null,所以就會報NullPointException的異常了。

②如果使用load方式來載入對象,當我們試圖得到一個id不存在的對象時,此時會報ObjectNotFoundException異常:

session = HibernateUtil.openSession();
/*
* 當通過get方式試圖得到一個id不存在的user對象時,此時會報ObjectNotFoundException異常
*/
User user = (User)session.load(User.class, 20);
System.out.println(user.getId());
System.out.println(user.getUsername());

我們看看控制台的輸出:

20
Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.yiidian.bean.User#20]......

為什麼使用load的方式和get的方式來得到一個不存在的對象報的異常不同呢??其原因還是因為load的延遲載入機制,使用load時,此時的user對象是一個代理對象,僅僅保存了當前的這個id值,當我們試圖得到該對象的username屬性時,這個屬性其實是不存在的,所以就會報出ObjectNotFoundException這個異常了。

③org.hibernate.LazyInitializationException異常

接下來我們再來看一個例子:

public class UserDAO
{
    public User loadUser(int id)
    {
        Session session = null;
        Transaction tx = null;
        User user =  null;
        try
        {
            session = HibernateUtil.openSession();
            tx = session.beginTransaction();
            user = (User)session.load(User.class, 1);
            tx.commit();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            tx.rollback();
        }
        finally
        {
            HibernateUtil.close(session);
        }
        return user;
    }
}
 

@Test
public void testLazy06(){
        UserDAO userDAO = new UserDAO();
        User user = userDAO.loadUser(2);
        System.out.println(user);
}

模擬了一個UserDAO這樣的對象,然後我們在測試用例裡面來通過load載入一個對象,此時我們發現控制台會報LazyInitializationException異常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session  .............

這個異常是什麼原因呢??還是因為load的延遲載入機制,當我們通過load()方法來載入一個對象時,此時並沒有發出sql語句去從資料庫中查詢出該對象,當前這個對象僅僅是一個只有id的代理對象,我們還並沒有使用該對象,但是此時我們的session已經關閉了,所以當我們在測試用例中使用該對象時就會報LazyInitializationException這個異常了。

所以以後我們只要看到控制台報LazyInitializationException這種異常,就知道是使用了load的方式延遲載入一個對象了,解決這個的方法有兩種,一種是將load改成get的方式來得到該對象,另一種是在表示層來開啟我們的session和關閉session。

file

歡迎關註我的公眾號::一點教程。獲得獨家整理的學習資源和日常乾貨推送。
如果您對我的系列教程感興趣,也可以關註我的網站:yiidian.com


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這是我的第一篇隨筆,當然是發我寫的第一個游戲啦! 大一(本人現在大二)寒假過完年,在家待著想起放假前計劃寫一個游戲的,因為本人立志走游戲開發這條路,加上大一上冊學了C語言,就想寫個游戲練練手。想了很久,最後決定寫一個俄羅斯方塊。 萬事開頭難,一開始真的不知道從何下手,所以百度查了一些資料(程式猿必須 ...
  • 1. web.xml中url pattern配置 url pattern為/ 使用SpringMVC的框架時,需要在 配置前端控制器 ,配置為: url pattern為/ 我們需要使用過濾器時,需要在 中進行註冊。以處理中文亂碼的過濾器 為例,配置為: url pattern為 .do 使用Str ...
  • [TOC] pandas可以進行數據輸入和輸出,有以下幾種類型:讀取文本文件及硬碟上其他更高效的格式文件,從資料庫中載入數據,於網路資源進行交互(比如Web API)。 下麵進行不同文本文件的讀取和寫入操作講解,首先進行文本格式數據的讀寫講解。 一:文本格式數據的讀寫 將表格型數據讀取為DataFr ...
  • 原文: "Java Garbage Collection Algorithms [till Java 9]" 垃圾回收(Garbage collection,GC)一直是 Java 流行背後的重要特性之一。垃圾回收是 Java 中用於釋放未使用記憶體的機制。本質上,它跟蹤所有仍在使用的對象,並將其餘的 ...
  • 前言 AQS一共花了5篇文章,對裡面實現的核心源碼都做了註解 也和大家詳細描述了下,後面的幾篇文字我將和大家聊聊一下AQS的實際使用,主要會聊幾張鎖,第一篇我會和大家聊下ReentrantLock 重入鎖,雖然在講AQS中也穿插了講了一下,但是我還是深入的聊下 ==PS:前面5篇寫在了CSDN裡面 ...
  • SpringCloud版本:Finchley.SR2 SpringBoot版本:2.0.3.RELEASE 源碼地址:https://gitee.com/bingqilinpeishenme/Java Tutorials 前言 寫博客一個多月了,斷斷續續的更新,今天有小伙伴催更新了,很高興,說明我的 ...
  • 前言 最近想起半年前鴿下來的Haskell,重溫了一下忘得精光的語法,讀了幾個示常式序,挺帶感的,於是函數式編程的草就種得更深了。又去Google了一下C++與FP,找到了一份近乎完美的講義,然後被帶到C++20的ranges library,對即將發佈的C++20滿懷憧憬。此時,我猛然間意識到,看 ...
  • ​ 1.問題 1、如何理解類文件結構佈局? 2、如何應用類載入器的工作原理進行將應用輾轉騰挪? 3、熱部署與熱替換有何區別,如何隔離類衝突? 4、JVM如何管理記憶體,有何記憶體淘汰機制? 5、JVM執行引擎的工作機制是什麼? 6、JVM調優應該遵循什麼原則,使用什麼工具? 7、JPDA架構是什麼,如何 ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...