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

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员猫爪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值