首页 > 其他分享 >Hibernate(Spring Data)抓取策略

Hibernate(Spring Data)抓取策略

时间:2023-09-03 22:01:15浏览次数:30  
标签:Loading Spring private 查询 Hibernate 关联 Data public 加载



文章目录

  • 示例代码放到最后,使用的是Springboot 项目
  • 1. 简介
  • 2. Hibernate抓取策略分类
  • 2.1 即时加载(Eager Loading)
  • 2.2 延迟加载(Lazy Loading)
  • 2.3 子查询加载(Subselect Loading)
  • 2.4 基于批处理的加载(Batch Loading)
  • 3. 即时加载(Eager Loading)
  • 3.1 概述
  • 3.2 实体类映射配置
  • 3.3 使用场景和注意事项
  • 4. 延迟加载(Lazy Loading)
  • 4.1 概述
  • 4.2 实体类映射配置
  • 4.3 使用场景和注意事项
  • 5. 子查询加载(Subselect Loading)
  • 5.1 概述
  • 5.2 实体类映射配置
  • 5.3 使用场景和注意事项
  • 6. 基于批处理的加载(Batch Loading)
  • 6.1 概述
  • 6.2 实体类映射配置
  • 6.3 使用场景和注意事项
  • 7. 总结
  • Demo


示例代码放到最后,使用的是Springboot 项目

1. 简介

本文将深入讨论Hibernate中的抓取策略,介绍不同类型的抓取策略以及它们的使用场景和注意事项。

2. Hibernate抓取策略分类

2.1 即时加载(Eager Loading)

即时加载是指在查询主实体时立即加载相关联的实体对象。这种策略会在查询时一次性加载所有关联的实体对象,可以减少数据库查询次数。

2.2 延迟加载(Lazy Loading)

延迟加载是指在访问关联属性时才会真正加载相关的实体对象。这种策略在查询主实体时只会加载主实体对象,而关联的实体对象只有在被访问时才会被加载。

2.3 子查询加载(Subselect Loading)

子查询加载是指通过执行子查询来加载关联的实体集合对象,而不是通过单独的SQL语句执行关联查询。这种策略适用于一对多或多对多关系,并可以提高性能。

2.4 基于批处理的加载(Batch Loading)

基于批处理的加载是指通过执行批量SQL语句一次性加载多个实体对象。这种策略可以减少数据库交互次数,提高性能。

3. 即时加载(Eager Loading)

3.1 概述

即时加载策略可以通过设置@ManyToOne@OneToOne等注解来实现,默认情况下Hibernate会使用即时加载进行关联对象的加载。

3.2 实体类映射配置

在关联属性上使用fetch = FetchType.EAGER注解来指定即时加载策略。

@Entity
@Data
public class Classes {
	@Id
	private int id;
	
	private String name;
	@OneToMany(mappedBy = "classes", fetch = FetchType.EAGER)
	private List<Student> students;
}

这里可以看到查询的班级实体种student属性集合有二十个对象

Hibernate(Spring Data)抓取策略_java

3.3 使用场景和注意事项

  • 适用于关联实体对象数据量较小且经常被使用的情况。
  • 频繁加载大量关联对象可能导致性能问题,需要谨慎使用。

4. 延迟加载(Lazy Loading)

4.1 概述

延迟加载策略可以通过设置@ManyToOne@OneToOne等注解来实现,默认情况下Hibernate会使用延迟加载进行关联对象的加载。

4.2 实体类映射配置

在关联属性上使用fetch = FetchType.LAZY注解来指定延迟加载策略。

@Entity
public class Classes{
    // ...

	@OneToMany(mappedBy = "classes", fetch = FetchType.LAZY)
	private List<Student> students;

    // ...
}

这里开启懒加载后查询到的对象种数据是空的,只有当执行get方法时才会去获取数据

Hibernate(Spring Data)抓取策略_加载_02

Hibernate(Spring Data)抓取策略_延迟加载_03

4.3 使用场景和注意事项

  • 适用于关联实体对象数据量较大或者不经常被使用的情况,可以减少不必要的数据库查询。
  • 注意检查在延迟加载策略下可能引发的懒加载异常,需要合理处理。

5. 子查询加载(Subselect Loading)

5.1 概述

子查询加载策略通过执行子查询来加载关联的实体集合对象,适用于一对多或多对多关系。

5.2 实体类映射配置

在关联集合属性上使用@Fetch注解,并指定@Fetch(FetchMode.SUBSELECT)来启用子查询加载策略。

@Entity
public class Order {
    // ...

    @OneToMany(mappedBy = "order")
    @Fetch(FetchMode.SUBSELECT)
    private List<OrderItem> orderItems;

    // ...
}

5.3 使用场景和注意事项

  • 适用于一对多或多对多的关联关系,减少关联集合对象的查询次数,提高性能。
  • 子查询加载策略会执行多条SQL语句,需要考虑数据库性能和查询效率的平衡。

6. 基于批处理的加载(Batch Loading)

6.1 概述

基于批处理的加载策略通过执行批量SQL语句一次性加载多个实体对象,减少数据库交互次数,提高性能。

6.2 实体类映射配置

在关联集合属性上使用@BatchSize注解,并指定要批量加载的大小。

@Entity
public class Order {
    // ...

    @OneToMany(mappedBy = "order")
    @BatchSize(size = 10)
    private List<OrderItem> orderItems;

    // ...
}

@BatchSize 注解的作用是为了优化 Hibernate 对关联集合属性的查询性能。它可以应用于实体类的集合属性上,告诉 Hibernate 在加载该集合属性时一次性加载指定个数的数据,从而减少数据库查询次数。

具体来说,@BatchSize 注解会影响到使用延迟加载(FetchType.LAZY)的关联集合属性的时候。当访问该集合属性时,如果该属性还没有被初始化,Hibernate 会触发查询加载数据。通过设置 @BatchSize 注解,可以控制同时加载的数据量,从而减少数据库查询的次数。

例如,假设我们有一个 EntityA 实体类,其中包含一个 List<EntityB> 类型的集合属性,我们可以在该属性上添加 @BatchSize 注解来优化查询性能:

@Entity
public class EntityA {
    // ...

    @OneToMany(mappedBy = "entityA", fetch = FetchType.LAZY)
    @BatchSize(size = 10) // 在这里添加注解
    private List<EntityB> entityBList;

    // getters and setters
}

在这个例子中,将 @BatchSize(size = 10) 注解应用于 entityBList 属性上。当访问 entityBList 属性时,Hibernate 会一次性加载 10 条 EntityB 数据,从而减少查询次数,提高性能。

需要注意的是,@BatchSize 注解只对延迟加载的集合属性有效,对于即时加载(FetchType.EAGER)的集合属性无效。此外,它只影响到关联集合属性本身的加载,不会影响到关联实体对象的加载。

总结来说,@BatchSize 注解可以优化延迟加载的关联集合属性的查询性能,通过一次加载多个数据项减少数据库查询次数。但需要根据具体情况选择合适的批处理大小,并综合考虑内存消耗和查询性能。

6.3 使用场景和注意事项

  • 适用于一对多或多对多的关联关系,减少数据库交互次数,提高性能。
  • 需要根据实际情况调整批量加载的大小,避免一次性加载过多数据导致内存占用过大。

7. 总结

Hibernate提供了多种抓取策略用于加载关联实体对象,包括即时加载、延迟加载、手动加载、子查询加载和基于批处理的加载。选择合适的抓取策略可以提高查询性能和减少数据库交互次数,但需要根据实际情况和性能要求进行综合考虑。

Demo

import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.List;
@Entity
@Data
public class Classes {
	@Id
	private int id;
	
	private String name;
//	@OneToMany(mappedBy = "classes")
//	private List<Student> students;

	//子查询加载
//	@OneToMany(mappedBy = "classes")
//	@Fetch(FetchMode.SUBSELECT)
//	private List<Student> students;


	 //基于批处理的加载
	@OneToMany(mappedBy = "classes")
	@BatchSize(size = 6)
	private List<Student> students;

	public void loadCustomer() {
		// 手动加载关联的Customer对象
		Hibernate.initialize(students);
	}

}

import lombok.Data;
import javax.persistence.*;

@Entity
@Data
public class Student {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	private String name;
	@ManyToOne(fetch = FetchType.EAGER)
	private Classes classes;

}
public interface JPAClassesDao extends JpaRepository<Classes, Integer>, Serializable {
}
public interface JPAStudentDao extends JpaRepository<Student, Integer> , Serializable {
}
@Autowired
    JPAStudentDao jpastudentDao;
    @Autowired
    JPAClassesDao jpaclassesDao;
//    @Resource
//    private  SessionFactory factory;
    @RequestMapping("/Insert")
    public void InsertClassesTest(){

        List<Classes> a=new ArrayList<>();
        List<Student> s=new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Classes b=new Classes();
            b.setId(i);
            b.setName("班级"+i);
            a.add(b);
            for (int j = 0; j < 20; j++) {
                Student c=new Student();
                c.setClasses(b);
                c.setName("学生"+i+j);
                s.add(c);
            }
        }
        jpaclassesDao.saveAll(a);
        jpastudentDao.saveAll(s);
    }


    @RequestMapping("/QueryEAGER")
    public void queryEAGERTest(){
        Classes byId = jpaclassesDao.findById(0).get();
        for (Student student : byId.getStudents()) {
            System.out.println("班级"+byId.getName()+"的:"+student.getName());
        }
    }
    @RequestMapping("/QueryLAZY")
    public void queryLAZYTest(){
        Classes byId = jpaclassesDao.getOne(1);
        System.out.println("--------------------------------------");
        for (Student student : byId.getStudents()) {
            System.out.println("班级"+byId.getName()+"的:"+student.getName());
        }
    }

    @RequestMapping("/QueryTriggerLAZY")
    public void queryTriggerTest(){
        Classes byId = jpaclassesDao.getOne(1);
       // byId.loadCustomer();
        for (Student student : byId.getStudents()) {
            System.out.println("班级"+byId.getName()+"的:"+student.getName());
        }
    }


    @RequestMapping("/QuerySubselect")
    public void querySubselectTest(){
        Classes byId = jpaclassesDao.getOne(1);
        for (Student student : byId.getStudents()) {
            System.out.println("班级"+byId.getName()+"的:"+student.getName());
        }
    }
<!-- hibernate依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
                <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>


标签:Loading,Spring,private,查询,Hibernate,关联,Data,public,加载
From: https://blog.51cto.com/u_15918766/7343565

相关文章

  • Hibernate(Spring-Data)3种实体继承创建表方式指南
    文章目录引言1.Hibernate实体继承概述1.1继承的概念和作用1.2Hibernate中的实体继承方式1.3基础注解2.单表继承策略2.1概述2.2表结构设计2.3实体类映射配置3.具体类继承策略3.1概述3.2表结构设计3.3实体类映射配置4.映射超类策略(每个类一张表)4.1概述4.2表结构......
  • springboot自动配置的原理和如何自定义starter
    一、springboot自动配置的原理使用springboot时的一大优点就是当需要引入一些第三方的框架时只需要引入一个对应的starter后springboot就会自动的完成配置,例如在springboot中使用mybatis只需要引入mybatis提供的starter.那么这种便捷的配置方式是如何实现的呢,要了解其中的原理......
  • SOFABoot和Springboot的关系
    SOFABoot也是SOFA技术栈体系中一个框架,但和SOFARPC没有直接关系,SOFABoot是一个SpringBoot加强版,还提供了方便使用SOFA中间件的能力,SOFARPC只是其中之一而已。二、功能描述SpringBoot虽然是一个非常优秀的主流开源框架,但在蚂蚁内部会遇到很多问题,比如说SpringBoot......
  • 【Azure Service Bus】使用Spring Cloud integration示例代码,为多个 Service Bus的连
    问题描述查看ServiceBus的Java示例代码,发现使用SpringCloudIntegration,配置Application.yaml可以连接到两个ServiceBus。但代码中没有使用ConnectionString属性配置服务连接。 那么,是否可以直接在此添加connection-string配置后,不用修改代码就可以连接到ServiceBus服务......
  • 【Azure Service Bus】使用Spring Cloud integration示例代码,为多个 Service Bus的连
    问题描述查看ServiceBus的Java示例代码,发现使用SpringCloudIntegration,配置Application.yaml可以连接到两个ServiceBus。但代码中没有使用ConnectionString属性配置服务连接。 那么,是否可以直接在此添加connection-string配置后,不用修改代码就可以连接到ServiceBu......
  • Java:SpringBoot实现定时任务Scheduled
    代码示例packagecom.example.demo.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.EnableScheduling;importorg.springframework.scheduling.annotation.Scheduled;importjava.text.SimpleDat......
  • [SpringSecurity5.6.2源码分析一]:spring.factories下有关SpringSecurity的配置类
    1、Spring.factories• 从下图可以看出spring-boot-autoconfigure/META-INF/spring.factories中关于SpringSecurity的自动配置类有以下这些org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\org.springframework.boot.autoconfigure.securi......
  • SpringSecurity
    快速入门1.介绍springsecurity是安全框架,准确来说是安全管理框架。相比与另外一个安全框架Shiro,springsecurity提供了更丰富的功能,社区资源也比Shiro丰富springsecurity框架用于Web应用的需要进行认证​和授权​认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪......
  • springboot的管理系统连接虚拟机数据库
    1、在配置文件里面进行更改原来的localhost更改为:虚拟机的IP地址:3306用户名密码更改为:Linux系统MYSQL的帐号密码2、有时因为权限不够,就需要进行权限的授予GRANTALLPRIVILEGESON*.*TO'root'@'%'IDENTIFIEDBY'wingkin45';然后就可能会出现这样的问题:我们可能需......
  • SpringBoot管理系统连接虚拟机MYSQL数据库
    1、使用Navicat软件连接虚拟机ip地址填写虚拟机的:192.168.158.129;密码填写虚拟机的mysql的密码:wingkin45;发现弹出这样一个提示框:2、在虚拟机中查看网络端口信息netstat-ntpl找到3306端口;3、在虚拟机中查看防火墙的状态systemctlstatusfirewalld没有3306端口,则就是......