Hibernate学习笔记-懒加载Lazy-true

本文详细介绍了懒加载技术的概念、应用场景及原理,通过对比Hibernate框架中get()与load()方法的区别,阐述了懒加载如何减少不必要的资源消耗,提高系统性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 懒加载概述以及使用情景

描述:懒加载(lazy),简单说就是延时、延迟加载。
情景:在Hibernate框架应用中,就是当我们要访问的数据量过大时,使用缓存并不太合适,因为内存容量有限 ,为了减少系统资源的消耗,减少并发量,这时需要用懒加载机制来弥补这种缺陷,但是这并不意味用了懒加载总体性能就提高了。
应用:
比如学校school和学生student,学校与学生1对多,如果lazy设置为 false,那么只要加载了一个学校的信息,就会根据一对多配置的关系把所有学生的信息也加载出来。但是实际上有时候只是需要用到学校的信息,不需要用到 学生的信息,这时学生信息的加载就等于浪费资源。如果lazy设置为true,那么只有当你访问学校信息的学生信息时候才会去加载学生的信息的信息。

2. 懒加载的原理
在Hibernate中运用session进行查询时,有get()和load()两个方法,先说一下两者的区别:
这两种方法的不同就是load()拥有懒加载的特性。Load()方法就是在查询某一条数据的时候并不会直接将这条数据以指定对象的形式来返回,而是在你真正需要使用该对象里面的一些属性的时候才会去数据库访问并得到数据。他的好处就是可以减少程序本身因为与数据库频繁的交互造成的处理速度缓慢。
* session.get()
* 1、方法加载出来的对象是class对象
* 2、在session.get方法执行的时候发出sql语句
* 3、class对象是有值的
* session.load ()
* 1、方法加载出来的对象是class的代理对象
* 2、在加载其属性的时候发出sql语句(按照需求加载,延迟加载)
* 3、获取标识符(UUID)属性是不用延迟加载的,获取普通属性是需要发出sql语句的
在此以User类为例

    public static void query(int id){
           Session session=null;
            try{
                session=HibernateUtil.getSession();
                User user=(User) session.load(User.class, id);
                //System.out.println(user.getName());
                System.out.println(user.getClass());
            }catch(HibernateExceptionex){
                ex.printStackTrace();
            }finally{
                if(session!=null){
                   session.close();
                }
            }
    }

运行上述方法后,我们并没有看到Hibernate打印任何查询语句,当将注释的语句打开,可以查询到的User的name。这时我们可以看到Hibernate产生的查询语句并看到user的name属性。这就是懒加载了。

3.懒加载代理对象

通过打印user.getClass()方法来验证,打印出来的结果并不是null,其实是代理对象,而这个对象所属的类是User类的子类,是Hibernate自动实现的一个子类。
代理对象的生命周期是什么呢?

    public static User query(int id){
           Session session=null;
           User User=null;
            try{
                session=HibernateUtil.getSession();
                User=(User)session.load(User.class, id);
                //System.out.println(User.getName());
            }catch(HibernateExceptionex){
                ex.printStackTrace();
            }finally{
                if(session!=null){
                   session.close();
                }
            }
            return User;
        }

//会抛出一个org.hibernate.LazyInitializationException异常
这说明懒加载的时候如果想通过代理对象查询数据库,需要在该session关闭以前才可以。但如果一定要在session关闭以后再使用代理对象的话,Hibernate中定义了一个初始化代理对象的方法initialize(),通过该方法即可将代理对象初始化。

4. 懒加载功能实现总结
1.通过Session.load()实现懒加载

load(Object, Serializable):根据id查询 。查询返回的是代理对象,不会立刻访问数据库,是懒加载的。当真正去使用对象的时候才会访问数据库。
用load()的时候会发现不会打印出查询语句,而使用get()的时候会打印出查询语句。
使用load()时如果在session关闭之后再查询此对象,会报异常:could not initialize proxy - no Session。处理办法:在session关闭之前初始化一下查询出来的对象:Hibernate.initialize(user);

使用load()可以提高效率,因为刚开始的时候并没有查询数据库。但很少使用。

2.one-to-one(元素)实现了懒加载。

在一对一的时候,查询主对象时默认不是懒加载。即:查询主对象的时候也会把从对象查询出来。

需要把主对象配制成lazy=”true” constrained=”true” fetch=”select”。此时查询主对象的时候就不会查询从对象,从而实现了懒加载。

一对一的时候,查询从对象的是默认是懒加载。即:查询从对象的时候不会把主对象查询出来。而是查询出来的是主对象的代理对象。

3.many-to-one(元素)实现了懒加载。

多对一的时候,查询主对象时默认是懒加载。即:查询主对象的时候不会把从对象查询出来。

多对一的时候,查询从对象时默认是懒加载。即:查询从对象的时候不会把主对象查询出来。

hibernate3.0中lazy有三个值,true,false,proxy,默认的是lazy=”proxy”.具体设置成什么要看你的需求,并不是说哪个设置就是最好的。在与标签上:当为true时,会有懒加载特性,当为false时会产生N+1问题,比如一个学生对应一个班级,用一条SQL查出10个学生,当访问学生的班级属性时Hibernate会再产生10条SQL分别查出每个学生对应的班级.

lazy= 什么时候捉取

fetch= 捉取方式:select=关联查询;join=连接表的方式查询(效率高)

fetch=join时,lazy的设置将没有意义.
4. one-to-many(元素)懒加载:默认会懒加载,这是必须的,是重常用的。

一对多的时候,查询主对象时默认是懒加载。即:查询主对象的时候不会把从对象查询出来。

一对多的时候,查询从对象时默认是懒加载。即:查询从对象的时候不会把主对象查询出来。

需要配置主对象中的set集合lazy=”false” 这样就配置成是不懒加载了。或者配置抓取方式fetch=”join”也可以变成不懒加载。

<think>嗯,用户问的是Hibernate映射中的default-lazy="true"是什么意思。首先,我需要确定用户对Hibernate的理解程度。可能他们正在学习Hibernate,或者在开发中遇到了延迟加载的问题。 用户之前的问题是关于DTD中属性的默认值确认,现在转向Hibernate的配置,说明他们可能在配置实体映射,特别是延迟加载相关的设置。需要解释清楚default-lazy的作用,以及如何影响实体和关联的加载行为。 首先,回顾Hibernate的延迟加载机制。延迟加载是为了优化性能,避免不必要的数据库查询。default-lazy是设置在hibernate-mapping元素中的属性,影响当前映射文件中所有实体的默认行为。 需要明确,default-lazy="true"意味着默认启用延迟加载,但具体的实现可能因Hibernate版本而异。比如,在旧版本中,这可能仅影响普通属性的加载,而关联(如集合或many-to-one)可能有自己的默认值。但在较新版本中,Hibernate可能更智能地处理这些设置。 还要注意,用户可能会混淆default-lazy和具体的lazy属性(如集合的lazy设置)。需要区分全局默认和局部覆盖的情况。例如,如果在hibernate-mapping设置了default-lazy="true",但某个实体显式设置lazy="false",则该实体将立即加载,覆盖默认。 用户可能的问题包括:如何确认某个实体的实际加载行为,或者为什么他们的应用没有按预期延迟加载。需要说明配置的优先级和检查方法,比如查看日志或使用调试工具。 此外,要提醒用户不同Hibernate版本的行为差异,建议查阅对应版本的文档,因为新版本可能有不同的默认设置或废弃某些配置选项。 最后,总结default-lazy的作用,确保用户明白它是设置全局默认,但可以被更具体的配置覆盖,帮助他们在优化应用性能时做出正确配置。</think>在 Hibernate 的映射配置中,`hibernate-mapping` 元素的 `default-lazy="true"` 表示**设置当前映射文件(或作用域)内所有类和集合的默认延迟加载(Lazy Loading)行为为启用**。以下是详细解释: --- ### 一、核心概念 1. **延迟加载(Lazy Loading)** Hibernate 的核心优化策略之一,目的是**推迟对象或关联数据的加载时机**,直到实际需要访问这些数据时才从数据库查询。这能有效减少不必要的 SQL 查询,提升性能。 2. **`default-lazy` 的作用范围** - 定义在 `hibernate-mapping` 根元素中。 - 影响当前映射文件内所有 `<class>`(实体类)和 `<collection>`(集合关联)的**默认延迟行为**。 - 可通过局部配置(如 `<class lazy="...">` 或 `<set lazy="...">`)覆盖默认值。 --- ### 二、`default-lazy="true"` 的含义 #### 1. **对 `<class>` 的影响** - 若未显式配置某个 `<class>` 的 `lazy` 属性,则其实体的**普通属性**(非关联属性)默认会**立即加载**,而**关联对象**(如 `many-to-one`、`one-to-many` 等)的加载行为由关联自身的 `lazy` 配置决定。 - **注意**:Hibernate 3.x 后,实体类本身的延迟加载(即代理对象的生成)需显式配置 `<class lazy="true">`,`default-lazy="true"` 不会自动启用类的延迟代理。 #### 2. **对 `<collection>` 的影响** - 若未显式配置集合(如 `<set>`、`<list>`)的 `lazy` 属性,则默认启用延迟加载。例如: ```xml <hibernate-mapping default-lazy="true"> <class name="Order"> <!-- 未配置 lazy,但 default-lazy 对普通属性无效 --> <set name="items"> <!-- 默认 lazy="true" --> <!-- 集合会延迟加载 --> </set> </class> </hibernate-mapping> ``` --- ### 三、常见误解与注意事项 1. **`default-lazy="true"` 不作用于实体类的普通属性** - 实体类的普通属性(如 `String name`)默认总是立即加载。 - 若需对实体类生成延迟代理(即返回代理对象,直到调用非 `id` 方法时才加载数据),需显式配置 `<class lazy="true">`。 2. **延迟加载的优先级规则** - 局部配置 > `default-lazy`。例如: ```xml <hibernate-mapping default-lazy="true"> <class name="User" lazy="false"> <!-- 显式覆盖默认值 --> <!-- 此类的关联集合仍可能受 default-lazy 影响 --> </class> </hibernate-mapping> ``` 3. **Hibernate 版本的差异** - Hibernate 5.x 后,集合的默认延迟行为从 `lazy="true"` 改为 `lazy="extra"`(更智能的延迟策略)。 - 建议结合具体版本文档验证行为。 --- ### 四、实际效果示例 #### 场景 1:默认配置 ```xml <hibernate-mapping default-lazy="true"> <class name="Product"> <set name="reviews"> <!-- 未显式设置 lazy --> <!-- 默认 lazy="true",集合延迟加载 --> </set> </class> </hibernate-mapping> ``` - **行为**:加载 `Product` 对象时,`reviews` 集合不会立即查询数据库,只有在调用 `product.getReviews()` 时才会触发加载。 #### 场景 2:显式覆盖 ```xml <hibernate-mapping default-lazy="true"> <class name="Product"> <set name="reviews" lazy="false"> <!-- 强制立即加载 --> </set> </class> </hibernate-mapping> ``` - **行为**:加载 `Product` 对象时,`reviews` 集合会立即通过 `JOIN` 或额外 SQL 加载。 --- ### 五、总结 | 配置项 | 作用范围 | 默认行为(Hibernate 3.x+) | |-------------------------|---------------|--------------------------------------------| | `hibernate-mapping default-lazy="true"` | 当前映射文件 | 对集合(`<set>`、`<list>` 等)默认启用延迟加载,但对实体类普通属性无效。 | | `<class lazy="true">` | 单个实体类 | 实体类返回代理对象,延迟加载普通属性(需显式配置)。 | | `<set lazy="true">` | 单个集合关联 | 集合延迟加载(默认受 `default-lazy` 影响)。 | **建议**: - 优先通过局部配置(如 `<set lazy="...">`)明确行为,避免依赖全局默认值。 - 通过 Hibernate 的 `show_sql` 配置或日志观察 SQL 生成,验证延迟加载是否生效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DYanchao2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值