Hibernate (Spring Data) fetching strategy

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, @OneToOneand 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.EAGERto 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.
Insert image description here

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, @OneToOneand 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.LAZYto 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.
Insert image description here

Insert image description here

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 @Fetchand 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 @BatchSizeand specify the size to batch load.

@Entity
public class Order {
    
    
    // ...

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

    // ...
}

@BatchSizeThe 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, @BatchSizethe 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 @BatchSizeannotations, 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 EntityAentity class that contains a List<EntityB>collection property of type, we can add an annotation on this property @BatchSizeto 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 entityBListto the attribute. When accessing entityBListproperties, Hibernate will load 10 pieces EntityBof data at one time, thereby reducing the number of queries and improving performance.

It should be noted that @BatchSizethe 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, @BatchSizeannotations 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>

Guess you like

Origin blog.csdn.net/pengjun_ge/article/details/132608035