Hibernate的检索策略(lazy、fetch、batch-size)

Hibernate的检索策略包括立即检索和延迟检索,可以在配置文件中通过对lazy、fetch、batch-size属性的设置来进行控制。一对多、多对多、多对一和一对一关系下的不同检索策略将影响对数据库访问的效率。

检索策略

  1. 立即检索,立即加载检索方法指定的对象
  2. 延迟检索,延迟加载检索方法指定的对象,在使用具体属性值时,才进行加载(这个时候会执行查询语句)

检索策略使用场景

  1. 如果加载对象是为了访问他的属性,则使用立即加载
  2. 如果加载对象目的是为了获得他的应用,则可以使用延迟加载
     

检索策略属性

以一个老师有多个学生,一对多的关系为例

  1. lazy: 主要决定students集合被初始化的时机. 即到底是在加载 Teacher对象时就被初始化, 还是在程序访问 students 集合时被初始化
  2. fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 students的查询语句的形式; 若取值为”join”, 则决定 students 集合被初始化的时机,若把 fetch 设置为 “join”, lazy 属性将被忽略
  3. batch-size:批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能

一对多和多对多的检索策略,lazy和fetch取值对应策略

  1. lazy=true ——– fatch=默认 ——– 采用延迟检索
  2. lazy=false ——– fatch=默认 ——– 采用立即检索
  3. lazy=extra ——– fatch=默认 ——– 采用加强延迟检索(延迟对象集合初始化时机)
  4. lazy=true/false/extra ——– fatch=默认 ——– 根据lazy决定执行检索策略
  5. lazy=true/false/extra ——– fatch=subselect ——– 根据lazy决定执行检索策略
  6. lazy=默认 ——– fatch=join ——– 采用迫切左外连接策略

多对一和一对一的检索策略,lazy和fetch取值对应策略

  1. lazy=proxy ——– fetch=默认 ——– 采用延迟检索
  2. lazy=non-proxy ——– fetch=默认 ——– 采用无代理延迟检索(需要增强持久化类的字节码才能实现)
  3. lazy=false ——– fetch=默认 ——– 采用立即检索
  4. lazy=默认 ——– fetch=join ——– 采用迫切左外连接策略(比立即检索用更少select语句)

实例验证

以下以学生与老师,多对多的关系为例

  1. 实体类
    学生
    package test.hibernate.spring.model;
    
    import java.util.HashSet;
    import java.util.Set;
    
    public class Student {
    	private int id;
    	private String name;
    	private Set  teachers=new HashSet<>();
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Set getTeachers() {
    		return teachers;
    	}
    	public void setTeachers(Set teachers) {
    		this.teachers = teachers;
    	}
    	public Student() {
    		super();
    	}
    	@Override
    	public String toString() {
    		return "Student [id=" + id + ", name=" + name + "]";
    	}
    	
    }

    老师

    package test.hibernate.spring.model;
    
    import java.util.HashSet;
    import java.util.Set;
    
    public class Teacher {
    	private int id;
    	private String name;
    	private Set students=new HashSet<>();
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Set getStudents() {
    		return students;
    	}
    	public void setStudents(Set students) {
    		this.students = students;
    	}
    	public Teacher() {
    		super();
    	}
    	@Override
    	public String toString() {
    		return "Teacher [id=" + id + ", name=" + name + "]";
    	}
    	
    	
    
    }

  2. 配置文件
    Student.hbm.xml
    
    
    
    	
        
            
                
                
            
            
                
            
            
            
            
                
                    
                
                
            
        
    
    

    Teacher.hbm.xml
    
    
    
        
            
                
                
            
            
                
            
            
                
                    
                
                
            
        
    
    

  3. 测试
/**
*Description:
*author: ljd
*@date 2024年7月30日 
*@version 1.0 
*/
package test.hibernate.spring;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import org.hibernate.service.ServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import test.hibernate.spring.model.Student;

public class TestSession {
	SessionFactory sessionFactory = null;
	Session session = null;
	Transaction ts = null;

	@Before
	public void beforP() {
		System.out.println("begin....");
		/* hibernate规定,所有的配置或服务,必须配置或注册到一个服务注册类中 */
		Configuration configuration = new Configuration().configure();
		ServiceRegistry sr = configuration.getStandardServiceRegistryBuilder().build();
		/* 从注册类中获得工厂类 */
		sessionFactory = new MetadataSources(sr).buildMetadata().buildSessionFactory();
		/* 通过工厂类开启Session */
		session = sessionFactory.openSession();
		/* 开启事务 */
		ts = session.beginTransaction();
	}

	@After
	public void endP() {
		System.out.println("end....");
		/* 提交事务 */
		ts.commit();
		/* 关闭Session */
		session.close();
		/* 关闭工厂 */
		sessionFactory.close();
	}

//	@Test
	public void testGet() {
		// 使用get时, class标签中lazy值不管是true还是false都会直接加载,当set标签
		// 中fetch="join"时,会在get时使用左join将其集体一起检索出来,访问数据库只需一次
		// fetch值是其它时则需要访两次
		Student s = session.get(Student.class, 1);
		System.out.println(s.getTeachers().size());
	}

//	@Test
	public void testLoad() {
		// 使用load时, class标签中lazy是true时不会直接加载,是false时会直接加载
		Student s = session.load(Student.class, 1);
		// 类中的集合是否直接检索,取决于类是否是直接加载,如果类是懒加载,那么集合将是在访问时才会检索
		System.out.println(s.getTeachers().size());
	}

	@Test
	public void testBatchSize() {
		String sql = "from Student";
		@SuppressWarnings("unchecked")
		Query query = session.createQuery(sql);
		List students = query.list();
		for (Student s : students) {
			System.out.println(s.getTeachers().size());
			System.out.println("-----------------------------");
		}
	}
}

你可能感兴趣的:(Hibernate,hibernate,batch,java)