Hibernate的抓取策略---Hibernate查詢方式的優化 延遲加載 + 抓取策略

Hibernate的抓取策略
立即檢索:當執行某行代碼的時候,馬上發出SQL語句進行查詢(get())
延遲檢索:當執行某行代碼的時候,不會馬上發出SQL語句進行查詢.當真正使用這個對象的時候纔會發送SQL語句(load())
建立表
在這裏插入圖片描述
建立兩個對象
在這裏插入圖片描述
設置工具類
在這裏插入圖片描述
關於Hibernate的更多配置信息請訪問我的另外一篇博客
https://blog.csdn.net/qq_44757034/article/details/106242492

一、延遲加載

1、延遲加載的概述

延遲加載:lazy(懶加載)。
執行搭配該行代碼的時候,不會發送語句進行查詢,在真正使用這個對象的屬性的時候纔會發送SQL語句進行查詢。

2、延遲加載的分類

(1)類級別的延遲加載:

指的是通過load方法查詢某個對象的時候,是否採用延遲。 session.load(要查詢類.class,1l);

a、類級別的延遲配置

在Customer的映射文件當中
在這裏插入圖片描述
默認lazy的值是true,

@Test
	// 類級別的延遲加載
	// 在<class> 的標籤上去配置的lazy
	public void demo01() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		Customer customer = session.load(Customer.class, 1l);//這裏不會發送SQL語句
		System.out.println(customer);//這裏纔會發送SQL語句
		tx.commit();
	}

不會馬上發送SQL語句,當真正使用該對象的時候,纔會發送SQL語句。
在這裏插入圖片描述
在這裏插入圖片描述
再次運行,映射文件上的lazy屬性設置爲false,當然也可以將這個持久化類改爲final修飾,這樣該類就無法生成代理,使延遲加載失效。延遲加載失敗。直接發送語句並打印輸出。

Customer customer = session.load(Customer.class, 1l);//這裏就會發生SQL語句

在這裏插入圖片描述

類級別的延遲加載可以通過上的lazy進行配置。

b、如果想讓lazy失效。

i、將lazy設置爲false,class上的lazy只對當前對象的屬性有效,對關聯對象的屬性無效
ii、將持久化類使用final修飾。
iii、lazy 是true 的情況下 Hibernate.isInitialized(customer);也可以是lazy失效,也就是延遲加載失效

(2)關聯級別的延遲加載:

指的是在查詢到某個對象的時候,在查詢其關聯對象的時候,是否會採用延遲加載
java要查詢類 類名稱=session.get(要查詢類.class,1l);
類名稱.get外鍵對應對象()----> 關聯級別的延遲
例如:

//Customer  代表客戶,LinlMan代表聯繫人
Customer customer = session.get(Customer.class,1l);
customer.getLinlMans(); //通過客戶獲得聯繫人,聯繫人對象是否採用了延遲加載,稱爲關聯級別的延遲。

抓取策略往往會和關聯級別的延遲加載一起使用,來優化語句。

二、抓取策略。

1、抓取策略的概述

(1)通過一個對象可以抓取到它的關聯對象,需要發送SQL語句,SQL語句如何方式,發送成什麼樣的個數通過策略來進行配置。

通過< set >或者是< many - to - one > 上通過fetch的屬性進行設置。
通過fetch和這些標籤上的 lazy如何設置來優化發送的SQL語句。

2、< set > 上的fetch和lazy

通過客戶獲取對應的聯繫人
在這裏插入圖片描述

fetch:抓取的策略,控制SQL語句的格式

select :默認值
join:發送一條迫切左外鏈接查詢關聯對象
subselect:發送一條子查詢去查詢其關聯對象

lazy:控制加載,控制查詢關聯對象的時候是否要採用延遲的。

true:默認值,查詢關聯對象的時候,默認情況下采用延遲加載。
(1)默認的情況下會發送一條普通的SQL語句:select語句,去查詢對應的關聯的對象
配置在Customer.hbm.xml
在這裏插入圖片描述

@Test
	// 默認情況:fetch="select" lazy="true"
	public void demo01() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 查詢1號客戶
		Customer customer = session.get(Customer.class, 1l);//發送一條查詢客戶的SQL語句
		System.out.println(customer.getCust_name());
		// 查看1號客戶的每個聯繫人的信息
		for (LinkMan LinkMan : customer.getLinkMans()) {//發送一條根據客戶的ID查詢聯繫人的SQL語句
			System.out.println(LinkMan.getLkm_name());// 獲得customer對應的所有Lkm_name
		}
		tx.commit();
	}

在這裏插入圖片描述
false:查詢關聯對象的時候不採用延遲加載。
(2)更改映射文件當中的fetch="select" lazy="false"

@Test
	// fetch="select" lazy="false"
	// 發送語句不延遲
	public void demo03() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 查詢1號客戶
		Customer customer = session.get(Customer.class, 1l);//查詢1號客戶並 發送一條查詢客戶的SQL語句
		System.out.println(customer.getCust_name());
		// 查看1號客戶的每個聯繫人的信息
		System.out.println(customer.getLinkMans().size());
		tx.commit();
	}

在這裏插入圖片描述
(3)extra:及其懶惰
在這裏插入圖片描述
當通過查詢到customer去獲取對應聯繫人的信息的時候,如果只是查詢數量,懶加載extra,只會發送select count() from ,來統計數量,不會向上面flase的將對應的聯繫人都查詢到。

@Test
	// fetch="select" lazy="extra"
	public void demo04() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 查詢1號客戶
		Customer customer = session.get(Customer.class, 1l);// 發送一條查詢1號客戶的SQL語句
		System.out.println(customer.getLinkMans().size());//發送select count() from ...
		tx.commit();
	}

在這裏插入圖片描述
(4)join:發送一條迫切左外鏈接查詢關聯對象
當fetch="join"的時候在lazy當中配置都是沒有作用的 --------> lazy失效
在這裏插入圖片描述

@Test
	// 設置fetch="join" lazy=true
	public void demo05() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		Customer customer = session.get(Customer.class, 1l);// 發送一條迫切左外鏈接查詢記錄
		System.out.println(customer.getCust_name());
		System.out.println(customer.getLinkMans().size());//不發送
		tx.commit();
	}

在這裏插入圖片描述
設置fetch=“join” lazy="false"
在這裏插入圖片描述
在這裏true和false的效果一樣,因爲join的功能就是迫切左外鏈接,查詢當前對象,並查詢對應左邊關聯的對象,已經全部查詢到,懶加載失效
(5)設置fetch=“subselect” lazy=“true”> subselect通過子查詢來查找對應的聯繫人
先發送SQL查詢對應的客戶,然後在獲取對應聯繫人信息的時候再發送一條SQL
在這裏插入圖片描述

@Test
	// 設置fetch="subselect" lazy="true"
	public void demo07() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		List<Customer> list = session.createQuery("from Customer").list();//發送查詢所有客戶的SQL語句
		for (Customer customer : list) {
			System.out.println(customer.getCust_name());
			System.out.println(customer.getLinkMans().size());//發送的一條子查詢,通過對象的外鍵匹配對應的聯繫人
		}
		tx.commit();
	}

在這裏插入圖片描述
在這裏插入圖片描述
(6)設置fetch=“subselect” lazy=“false” 查詢客戶並同時查詢對應的聯繫人
發送查詢客戶的語句,通過子查詢的方式統計對應的數據
在這裏插入圖片描述

@Test
	// 設置fetch="subselect" lazy="false"
	public void demo08() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//查詢客戶並同時查詢對應的聯繫人
		List<Customer> list = session.createQuery("from Customer").list();// 發送查詢客戶的語句,通過子查詢的方式統計對應的數據
		for (Customer customer : list) {
			System.out.println(customer.getCust_name());
			System.out.println(customer.getLinkMans().size());
		}
		tx.commit();
	}

在這裏插入圖片描述
在這裏插入圖片描述
(7)在實際的開發當中,我們一般都採用默認值。fetch=select lazy=true
如果有特殊的需求,可能需要配置join。

3、< many-to-one > 上的fetch和lazy

fetch:抓取策略,控制SQL語句的個數

select :(默認值):發送普通的select語句來,查詢對應關聯的對象
join:發送一條迫切左外鏈接

lazy:延遲加載,控制查詢關聯對象的時候是否採用延遲

proxy:(默認值):proxy具體的取值,取決於我們另一端上< class >上的lazy的值。如果class上的lazy是true
false:查詢關聯對象不採用延遲。
no-proxy:(不會使用)

測試方法:通過聯繫人查詢客戶

在LinkMan.hbm.xml當中配置對應的信息

(1)測試< many-to-one > 上的fetch和lazy默認值

先將Customer.hbm.xml當中的類級別的懶加載和抓取策略上的set的fecth和lazy的屬性全部去掉
測試
先發送一條查詢聯繫人的SQL語句,然後再發送一條查詢下客戶的SQL語句

@Test
	// 默認值LinkMan當中的many-to-one上的默認值
	public void demo01() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		LinkMan linkMan = session.get(LinkMan.class, 1l);//發送一條查詢聯繫人的語句
		System.out.println(linkMan.getLkm_name());
		System.out.println(linkMan.getCustomer().getCust_name());//發送一條查詢客戶的SQL語句
		tx.commit();
	}

在這裏插入圖片描述
然後在LinkMan.hbm.xml當中配置, <many-to-one>配置fetch="select" lazy="proxy"
在這裏插入圖片描述
再次運行代碼,結果和上述的結果一直則,證明,其默認值爲fetch="select" lazy="proxy"

(2)配置< many-to-one >上 <many-to-one>配置fetch="select" lazy="false"

發送SQL查詢聯繫人的信息併發送SQL查詢對應的客戶

@Test
	// <many-to-one>配置fetch="select" lazy="false"
	public void demo03() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//發送兩個select語句
		LinkMan linkMan = session.get(LinkMan.class, 1l);//發送SQL查詢聯繫人的信息併發送SQL查詢對應的客戶
		System.out.println(linkMan.getLkm_name());
		System.out.println(linkMan.getCustomer().getCust_name());
		tx.commit();
	}

在這裏插入圖片描述

(3)< many-to-one >配置fetch=“join” lazy=“失效”

發送一條迫切左外鏈接去查詢聯繫人所關聯的客戶

@Test
	// <many-to-one>配置fetch="join" lazy="失效"
	public void demo04() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 發送一條迫切左外鏈接去查詢聯繫人所關聯的客戶
		LinkMan linkMan = session.get(LinkMan.class, 1l);
		System.out.println(linkMan.getLkm_name());
		System.out.println(linkMan.getCustomer().getCust_name());
		tx.commit();
	}

在這裏插入圖片描述
false和proxy效果一樣
在這裏插入圖片描述

(4)proxy具體的取值,取決於我們另一端上< class >上的lazy的值。如果class上的lazy是true

a、設置 LinkMan.hbm.xml和Customer.hbm.xml
發送兩條查詢SQL語句
LinkMan.hbm.xml
在這裏插入圖片描述
Customer.hbm.xml
在這裏插入圖片描述
當中Customer.hbm.xml當中lazy爲ture的時候,相當於< many-to-one >當中的lazy=“false”

// <many-to-one>配置fetch="select" lazy="proxy"
	public void demo02() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		LinkMan linkMan = session.get(LinkMan.class, 1l);// 發送一條查詢聯繫人的語句
		System.out.println(linkMan.getLkm_name());
		System.out.println(linkMan.getCustomer().getCust_name());
		tx.commit();
	}

在這裏插入圖片描述
b、 LinkMan.hbm.xml當中的值不變,改變Customer.hbm.xml當中的數值
在這裏插入圖片描述
當class當中的lazy等於false的時候,當中< many-to-one >相當於lazy=“false”
再次運行上面代碼,同時發送兩個查詢SQL語句,查詢聯繫並查詢客戶
在這裏插入圖片描述

三、批量抓取策略。

1、什麼是批量抓取

一批關聯對象一起進行抓取,batch-size
一次獲取多個客戶的聯繫人信息

2、測試批量抓取:通過客戶獲取對應的聯繫人

(1)默認情況下:通過客戶獲取對應的聯繫人
@Test
	// 在獲取客戶的時候同時批量去抓取聯繫人
	public void demo01() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		List<Customer> list = session.createQuery("from Customer").list();
		for (Customer customer : list) {
			System.out.println(customer.getCust_name());
			for (LinkMan linkman : customer.getLinkMans()) {
				System.out.println(linkman.getLkm_name());			
			}
		}
		tx.commit();
	}

會發送很多查詢語句,效率比較底下
在這裏插入圖片描述

(2)在一 的一方配置batch-size=""

Customer.hbm.xml
batch-size="“代表當前對象是幾個爲一組發送SQL語句,超出的自動增加發送SQL語句的數量
發送SQL數量等於通過外鍵要查詢的數據總數除以batch-size=”" 當中的數,不夠加一
batch-size=""等於外鍵種類數量是最好的情況
在這裏插入圖片描述

@Test
	// 在獲取客戶的時候同時批量去抓取聯繫人
	public void demo01() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		List<Customer> list = session.createQuery("from Customer").list();
		for (Customer customer : list) {
			System.out.println("-------------------------------");
			System.out.println(customer.getCust_name());
			System.out.println("-------------------------------");
			for (LinkMan linkman : customer.getLinkMans()) {
				System.out.println(linkman.getLkm_name());
			}
		}
		tx.commit();
	}

在這裏插入圖片描述
在這裏插入圖片描述

3、測試批量抓取:在獲取聯繫人的時候同時批量去抓取客戶

(1)默認情況
	@Test
	// 在獲取聯繫人的時候同時批量去抓取客戶
	public void demo02() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		List<LinkMan> list = session.createQuery("from LinkMan").list();
		for (LinkMan linkMan : list) {
			System.out.println(linkMan.getLkm_name());//獲取到所有的聯繫人
			System.out.println(linkMan.getCustomer().getCust_name());//通過聯繫人去匹配對應的用戶
		}
		tx.commit();
	}

發送了五條查詢語句
查詢所有聯繫人,然後根據外鍵查詢對應的客戶
在這裏插入圖片描述

(2)雖然控制的時通過聯繫人查詢對應客戶,但是也得在客戶上去配置對應信息。

在Customer.hbm.xml上的配置
在這裏插入圖片描述
batch-size=“3"同時根據3個id進行查詢
發送SQL數量等於通過外鍵要查詢的數據總數除以batch-size=”" 當中的數,不夠加一

batch-size=""等於外鍵種類數量是最好的情況

	@Test
	// 在獲取聯繫人的時候同時批量去抓取客戶
	//在Customer.hbm.xml上的<class>配置
	public void demo02() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		List<LinkMan> list = session.createQuery("from LinkMan").list();
		for (LinkMan linkMan : list) {
			System.out.println(linkMan.getLkm_name());//獲取到所有的聯繫人
			
			System.out.println(linkMan.getCustomer().getCust_name());//通過聯繫人去匹配對應的用戶
		}
		tx.commit();
	}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章