Article directory
The sample code is put at the end, using the Springboot project
1 Introduction
This article will discuss the fetching strategies in Hibernate in depth, introducing different types of fetching strategies as well as their usage scenarios and precautions.
2. Hibernate crawling strategy classification
2.1 Eager Loading
Immediate loading means loading the associated entity objects immediately when querying the main entity. This strategy will load all associated entity objects at once during query, which can reduce the number of database queries.
2.2 Lazy Loading
Lazy loading means that the related entity objects are not actually loaded until the associated properties are accessed. This strategy will only load the main entity object when querying the main entity, and the associated entity objects will only be loaded when they are accessed.
2.3 Subselect Loading
Subquery loading refers to loading related entity collection objects by executing subqueries instead of executing related queries through separate SQL statements. This strategy works well for one-to-many or many-to-many relationships and can improve performance.
2.4 Batch Loading
Batch-based loading refers to loading multiple entity objects at one time by executing batch SQL statements. This strategy can reduce the number of database interactions and improve performance.
3. Eager Loading
3.1 Overview
The instant loading strategy can be implemented by setting @ManyToOne
, @OneToOne
and other annotations. By default, Hibernate will use instant loading to load associated objects.
3.2 Entity class mapping configuration
Use annotations on associated properties fetch = FetchType.EAGER
to specify an immediate loading strategy.
@Entity
@Data
public class Classes {
@Id
private int id;
private String name;
@OneToMany(mappedBy = "classes", fetch = FetchType.EAGER)
private List<Student> students;
}
Here you can see that the queried class entity type student attribute collection has twenty objects.
3.3 Usage scenarios and precautions
- It is suitable for situations where the data volume of associated entity objects is small and frequently used.
- Frequently loading a large number of related objects may cause performance problems and needs to be used with caution.
4. Lazy Loading
4.1 Overview
Lazy loading strategy can be implemented by setting @ManyToOne
, @OneToOne
and other annotations. By default, Hibernate will use lazy loading to load associated objects.
4.2 Entity class mapping configuration
Use annotations on associated properties fetch = FetchType.LAZY
to specify lazy loading strategies.
@Entity
public class Classes{
// ...
@OneToMany(mappedBy = "classes", fetch = FetchType.LAZY)
private List<Student> students;
// ...
}
The object data queried after lazy loading is enabled here is empty, and the data will only be obtained when the get method is executed.
4.3 Usage scenarios and precautions
- It is suitable for situations where the amount of associated entity object data is large or is not used frequently, and can reduce unnecessary database queries.
- Pay attention to check for lazy loading exceptions that may be caused under the lazy loading strategy and need to handle them appropriately.
5. Subselect Loading
5.1 Overview
The subquery loading strategy loads associated entity collection objects by executing subqueries, and is suitable for one-to-many or many-to-many relationships.
5.2 Entity class mapping configuration
Use annotations on the associated collection properties @Fetch
and specify @Fetch(FetchMode.SUBSELECT)
to enable the subquery loading strategy.
@Entity
public class Order {
// ...
@OneToMany(mappedBy = "order")
@Fetch(FetchMode.SUBSELECT)
private List<OrderItem> orderItems;
// ...
}
5.3 Usage scenarios and precautions
- It is suitable for one-to-many or many-to-many relationships, reducing the number of queries for associated collection objects and improving performance.
- The subquery loading strategy will execute multiple SQL statements, and the balance between database performance and query efficiency needs to be considered.
6. Batch Loading
6.1 Overview
The batch-based loading strategy loads multiple entity objects at once by executing batch SQL statements, reducing the number of database interactions and improving performance.
6.2 Entity class mapping configuration
Use annotations on the associated collection properties @BatchSize
and specify the size to batch load.
@Entity
public class Order {
// ...
@OneToMany(mappedBy = "order")
@BatchSize(size = 10)
private List<OrderItem> orderItems;
// ...
}
@BatchSize
The purpose of annotations is to optimize Hibernate's query performance for associated collection attributes. It can be applied to the collection properties of entity classes to tell Hibernate to load the specified number of data at one time when loading the collection properties, thereby reducing the number of database queries.
Specifically, @BatchSize
the annotation affects the use of lazy loading (FetchType.LAZY) associated collection properties. When accessing the collection property, if the property has not been initialized, Hibernate will trigger a query to load the data. By setting @BatchSize
annotations, you can control the amount of data loaded at the same time, thereby reducing the number of database queries.
For example, suppose we have an EntityA
entity class that contains a List<EntityB>
collection property of type, we can add an annotation on this property @BatchSize
to optimize query performance:
@Entity
public class EntityA {
// ...
@OneToMany(mappedBy = "entityA", fetch = FetchType.LAZY)
@BatchSize(size = 10) // 在这里添加注解
private List<EntityB> entityBList;
// getters and setters
}
In this example, @BatchSize(size = 10)
the annotation is applied entityBList
to the attribute. When accessing entityBList
properties, Hibernate will load 10 pieces EntityB
of data at one time, thereby reducing the number of queries and improving performance.
It should be noted that @BatchSize
the annotation is only valid for lazy-loaded collection properties and is not valid for immediate-loaded (FetchType.EAGER) collection properties. In addition, it only affects the loading of the associated collection attributes themselves and does not affect the loading of associated entity objects.
In summary, @BatchSize
annotations can optimize the query performance of lazy-loaded associated collection attributes and reduce the number of database queries by loading multiple data items at once. However, it is necessary to choose the appropriate batch size according to the specific situation, taking into account memory consumption and query performance.
6.3 Usage scenarios and precautions
- Suitable for one-to-many or many-to-many relationships, reducing the number of database interactions and improving performance.
- The size of batch loading needs to be adjusted according to the actual situation to avoid excessive memory usage caused by loading too much data at one time.
7. Summary
Hibernate provides a variety of fetching strategies for loading related entity objects, including immediate loading, lazy loading, manual loading, subquery loading and batch-based loading. Choosing an appropriate crawling strategy can improve query performance and reduce the number of database interactions, but it needs to be comprehensively considered based on the actual situation and performance requirements.
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>