Hibernate(41)Hibernate的延迟加载和急加载的区别是什么?

Hibernate的延迟加载和急加载

Hibernate中的延迟加载(Lazy Loading)和急加载(Eager Loading)是两种常见的数据加载策略,用于决定如何从数据库中加载关联实体。

  • 延迟加载(Lazy Loading):在访问关联实体时才加载数据。这种策略可以提高性能,因为只有在需要时才会访问数据库。
  • 急加载(Eager Loading):在加载主实体时立即加载所有关联实体。这种策略可以减少数据库访问次数,但可能会导致加载不必要的数据,从而影响性能。

配置延迟加载和急加载

在Hibernate中,我们可以通过使用JPA注解(如@OneToMany@ManyToOne@OneToOne@ManyToMany等)来指定加载策略。

示例代码

步骤一:定义实体类

我们假设有两个实体类ProductCategory,其中一个Product可以属于多个Category

java 复制代码
package com.example.domain;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "product")
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "price")
    private Double price;

    @ManyToMany(fetch = FetchType.LAZY) // 延迟加载
    @JoinTable(
        name = "product_category",
        joinColumns = @JoinColumn(name = "product_id"),
        inverseJoinColumns = @JoinColumn(name = "category_id")
    )
    private Set<Category> categories = new HashSet<>();

    // Getters 和 Setters

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Set<Category> getCategories() {
        return categories;
    }

    public void setCategories(Set<Category> categories) {
        this.categories = categories;
    }
}

@Entity
@Table(name = "category")
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToMany(mappedBy = "categories", fetch = FetchType.EAGER) // 急加载
    private Set<Product> products = new HashSet<>();

    // Getters 和 Setters

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Product> getProducts() {
        return products;
    }

    public void setProducts(Set<Product> products) {
        this.products = products;
    }
}

步骤二:配置Hibernate

我们仍然需要一个配置文件来配置Hibernate连接和映射。

Hibernate配置文件 hibernate.cfg.xml
xml 复制代码
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 数据库连接配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/your_database</property>
        <property name="hibernate.connection.username">your_username</property>
        <property name="hibernate.connection.password">your_password</property>

        <!-- Hibernate 属性配置 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">update</property>

        <!-- 映射类 -->
        <mapping class="com.example.domain.Product"/>
        <mapping class="com.example.domain.Category"/>
    </session-factory>
</hibernate-configuration>

步骤三:实用类HibernateUtil

java 复制代码
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

步骤四:测试延迟加载和急加载

通过一个简单的操作来测试延迟加载和急加载的效果。

测试类
java 复制代码
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.example.domain.Product;
import com.example.domain.Category;

public class HibernateLoadingStrategyExample {
    public static void main(String[] args) {
        // 获取SessionFactory
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        // 插入示例数据
        insertSampleData(sessionFactory);

        // 查询示例数据并测试加载策略
        testLoadingStrategies(sessionFactory);

        // 关闭SessionFactory
        sessionFactory.close();
    }

    private static void insertSampleData(SessionFactory sessionFactory) {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            Product product1 = new Product("Laptop", 1000.0);
            Product product2 = new Product("Smartphone", 500.0);

            Category category1 = new Category("Electronics");
            Category category2 = new Category("Mobile Devices");

            product1.getCategories().add(category1);
            product1.getCategories().add(category2);
            product2.getCategories().add(category2);

            category1.getProducts().add(product1);
            category2.getProducts().add(product1);
            category2.getProducts().add(product2);

            session.save(product1);
            session.save(product2);
            session.save(category1);
            session.save(category2);

            transaction.commit();
            System.out.println("Inserted sample data");
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    private static void testLoadingStrategies(SessionFactory sessionFactory) {
        Session session = sessionFactory.openSession();
        try {
            // Lazy Loading
            System.out.println("Testing Lazy Loading:");
            Product product = session.get(Product.class, 1L);
            System.out.println("Product: " + product.getName());
            System.out.println("Categories: " + product.getCategories().size()); // 这里会触发数据库查询

            // Eager Loading
            System.out.println("\nTesting Eager Loading:");
            Category category = session.get(Category.class, 1L);
            System.out.println("Category: " + category.getName());
            System.out.println("Products: " + category.getProducts().size()); // 这里不会触发额外的数据库查询
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
}

详细解释

  1. 定义实体类

    • Product类中,@ManyToMany关联使用了fetch = FetchType.LAZY,表示在访问categories集合时才加载数据。
    • Category类中,@ManyToMany关联使用了fetch = FetchType.EAGER,表示在加载Category实体时立即加载products集合。
  2. 配置文件

    • 标准的Hibernate配置文件,用于数据库连接和映射类的配置。
  3. 实用类HibernateUtil

    • 提供了创建和获取SessionFactory实例的方法。
  4. 测试类

    • 插入一些示例数据,包括一些ProductCategory实体,以及它们之间的关联关系。
    • 通过testLoadingStrategies方法来测试延迟加载和急加载的效果。对于延迟加载,在访问关联集合时会触发数据库查询;而对于急加载,关联集合会在加载主实体时立即加载。

通过这种方式,我们可以灵活地配置和测试Hibernate中的延迟加载和急加载策略,以优化应用程序的性能和数据访问效率。

相关推荐
猪猪拆迁队2 小时前
2025年终总结-都在喊前端已死,这一年我的焦虑、挣扎与重组:AI 时代如何摆正自己的位置
前端·后端·ai编程
ConardLi2 小时前
SFT、RAG 调优效率翻倍!垂直领域大模型评估实战指南
前端·javascript·后端
Hooray3 小时前
2026年,站在职业生涯十字路口的我该何去何从?
前端·后端
唐叔在学习3 小时前
还在申请云服务器来传输数据嘛?试试P2P直连吧
后端·python
开心猴爷3 小时前
iOS 代码混淆在项目中的方式, IPA 级保护实践记录
后端
魅影骑士00104 小时前
柯里化函数
后端·设计模式
JOEH604 小时前
🛡️ 微服务雪崩救星:Sentinel 限流熔断实战,3行代码搞定高可用!
后端·全栈
aiopencode4 小时前
iOS手动代码混淆函数和变量名基本原理和注意事项教程
后端
程序员威哥4 小时前
YOLOv8用ConvMixer结构:简化Backbone,速度+20%,mAP仅降0.9%
后端