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();
}