hibernate里的session.get()和session.load()区别以及Hibernate.initialize(Obj)用法

NHibernate延迟加载与DDD实践:代理机制深度解析 延迟加载是ORM框架的核心能力之一,其本质是在运行时按需加载关联数据,以平衡性能与内存开销。在.NET生态中,NHibernate通过动态代理实现该机制,深度结合C#的virtual特性与反射能力,既保障了领域模型的完整性,又支持领域驱动设计(DDD)所强调的业务逻辑内聚性。其技术价值不仅在于减少N+1查询,更在于为审计、软删除、租户隔离等横切关注点提供架构级支持。典型应用场景包括金融系统中的强一致性实体访问、SaaS多租户数据隔离,以及需要精细控制加载策略的复杂聚合根操作。本文聚焦NHibernate中延 阅读详情

有待深入研究hibernate缓存机制,先保存起来

最近面试别人,正好出的笔试题中有道关于Hibernate延迟加载的问题,聊天过程中发现很多人对Hibernate的延迟加载有些理解误区,写些东东在这里,希望对大家有所帮助。

首先是第一个误区:延迟加载只能作用于关联实体
看到这个是不是在想:非关联实体延迟加载有什么用?
为了解答上面这个问题,我们可以先考虑另一个问题:Hibernate Session的get和load方法有什么区别?
如果你的回答是:当方法参数为数据库不存在的id时,get会返回null,load会抛出异常,那么恭喜你,进入了第二个误区
如果此时你还想补充一下:load会从缓存中取出数据而get不会,再次恭喜,进入第三个误区

如果你在上面三个误区中有一个踏入了,那么我敢打赌,你一定是被网上那些半吊子的工程师们写的博客给戕害了。。。。
此时是不是很愤怒?这些长久以来你牢记在心的Hibernate的特性原来都是浮云。。。。

呵呵,接下来我们一个个来走出这些误区。
Mop上无图无真相,我们这里无码无真相——不要误会,我是说代码

首先看看第二个误区:当方法参数为数据库不存在的id时,get会返回null,load会抛出异常
如果你现在想说:没错啊,我自己就测试过,get确实返回了null,load确实抛出了异常。
那么请回答:load是在执行load语句时抛出异常的吗?为什么?如果你答不上来,那么接着看下面的代码吧:

view plaincopy to clipboardprint?
@Test(expected = IllegalArgumentException.class)  
public void 延迟加载() throws Exception {  
    // 启动  
    Session session = sessionFactory.openSession();  
    Transaction tx = session.beginTransaction();  
 
    User user = (User)session.load(User.class, 100L);  // 不存在的ID  
 
    try {  
        user.getName();  
    } catch (ObjectNotFoundException ex) {  
        // 命中数据库发现没有对象即抛出ObjectNotFoundException异常  
        throw new IllegalArgumentException("随便抛出一个不可能的异常");  
    }  
 
    tx.commit();  
    session.close();  
} 
@Test(expected = IllegalArgumentException.class)
public void 延迟加载() throws Exception {
    // 启动
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();

    User user = (User)session.load(User.class, 100L);  // 不存在的ID

    try {
        user.getName();
    } catch (ObjectNotFoundException ex) {
        // 命中数据库发现没有对象即抛出ObjectNotFoundException异常
        throw new IllegalArgumentException("随便抛出一个不可能的异常");
    }

    tx.commit();
    session.close();
}

 

由这个test case我们可以知道load并不是在执行时就马上抛出不存在数据的异常的(ObjectNotFoundException),这是为什么呢?再看代码:

view plaincopy to clipboardprint?
@Test(expected = IllegalArgumentException.class)  
public void 延迟加载() throws Exception {  
    // 启动  
    Session session = sessionFactory.openSession();  
    Transaction tx = session.beginTransaction();  
 
    User user = (User)session.load(User.class, 100L);  // 不存在的ID  
 
    Assert.assertTrue(user instanceof HibernateProxy);  
 
    user.getId();  // 由于ID是不被延迟加载的属性,因此不会抛出异常  
 
    try {  
        Hibernate.initialize(user);  // 此时才会触发命中数据库  
        //user.getName();  
    } catch (ObjectNotFoundException ex) {  
        // 命中数据库发现没有对象即抛出ObjectNotFoundException异常  
        throw new IllegalArgumentException("随便抛出一个不可能的异常");  
    }  
 
    tx.commit();  
    session.close();  
} 
@Test(expected = IllegalArgumentException.class)
public void 延迟加载() throws Exception {
    // 启动
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();

    User user = (User)session.load(User.class, 100L);  // 不存在的ID

    Assert.assertTrue(user instanceof HibernateProxy);

    user.getId();  // 由于ID是不被延迟加载的属性,因此不会抛出异常

    try {
        Hibernate.initialize(user);  // 此时才会触发命中数据库
        //user.getName();
    } catch (ObjectNotFoundException ex) {
        // 命中数据库发现没有对象即抛出ObjectNotFoundException异常
        throw new IllegalArgumentException("随便抛出一个不可能的异常");
    }

    tx.commit();
    session.close();
}

 

看高亮的几行,代码已经把问题说得很清楚了,get和load最大的区别是(假设缓存皆空的情况):get是立即命中数据库去查询这条记录,而load则是直接返回一个代理对象(HibernateProxy)而不命中数据库,换句话来说load是为单个对象进行了延迟加载,如果你不去访问这个对象的除ID外的属性,即使目标记录不存在它也永远都不会抛出异常。由于load不立即命中数据库,它确实有一定几率提高效率

OK,我想上面一段话应该可以解释第一和第二个误区了,那么第三个误区呢?
再看代码

view plaincopy to clipboardprint?
@Test 
public void get和load一级缓存测试() throws Exception {  
    // 启动  
    Session session = sessionFactory.openSession();  
    Transaction tx = session.beginTransaction();  
 
    // 验证load在缓存为空的情况下是否会使得加载的对象过一级缓存  
    User user1 = (User)session.load(User.class, 1L);  // 存在的ID,此时虽然没有解开Proxy但已经进入缓存  
    Assert.assertTrue(user1 instanceof HibernateProxy);  
    Hibernate.initialize(user1);  // 解开Proxy,会触发命中数据库操作  
    User user3 = (User)session.get(User.class, 1L);  
    Assert.assertTrue(user3 instanceof HibernateProxy);  // 即使使用get,但由于缓存中存储的是一个Proxy,所以这里得到的也是Proxy  
    Hibernate.initialize(user3);  // 解开Proxy,但不会命中数据库  
 
    // 验证在load一个不存在的ID后,不解开然后get  
    User user4 = (User)session.load(User.class, 100L);  // 不存在的ID,仍然将Proxy进入缓存  
    Assert.assertTrue(user4 instanceof HibernateProxy);  
    //Hibernate.initialize(user3);  // 不解开Proxy  
    try {  
        session.get(User.class, 100L);  // 得到Proxy,命中数据库尝试解开Proxy,由于ID不存在因此抛出异常  
        Assert.fail("ID不存在所以会出错,不会执行本条");  
    } catch (ObjectNotFoundException ex) {  
 
    }  
 
    // 清空缓存  
    session.clear();  
 
    // 验证缓存为空的情况下get是否为Proxy  
    User user6 = (User)session.get(User.class, 1L);  // 命中数据库,直接将组装完成的User实体进入缓存  
    Assert.assertTrue(!(user6 instanceof HibernateProxy));  
 
    // 验证get从缓存中取出对象  
    User user7 = (User)session.get(User.class, 1L);  
    Assert.assertTrue(!(user7 instanceof HibernateProxy)); // 缓存中是真实的User对象,get取出的就是真实的User对象  
 
    // 验证load是否从一级缓存取数据  
    User user8 = (User)session.load(User.class, 1L);  
    Assert.assertTrue(!(user8 instanceof HibernateProxy));  // 缓存中是真实的User对象,load取出的也是真实的User对象  
 
    tx.commit();  
    session.close();  
} 
@Test
public void get和load一级缓存测试() throws Exception {
    // 启动
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();

    // 验证load在缓存为空的情况下是否会使得加载的对象过一级缓存
    User user1 = (User)session.load(User.class, 1L);  // 存在的ID,此时虽然没有解开Proxy但已经进入缓存
    Assert.assertTrue(user1 instanceof HibernateProxy);
    Hibernate.initialize(user1);  // 解开Proxy,会触发命中数据库操作
    User user3 = (User)session.get(User.class, 1L);
    Assert.assertTrue(user3 instanceof HibernateProxy);  // 即使使用get,但由于缓存中存储的是一个Proxy,所以这里得到的也是Proxy
    Hibernate.initialize(user3);  // 解开Proxy,但不会命中数据库

    // 验证在load一个不存在的ID后,不解开然后get
    User user4 = (User)session.load(User.class, 100L);  // 不存在的ID,仍然将Proxy进入缓存
    Assert.assertTrue(user4 instanceof HibernateProxy);
    //Hibernate.initialize(user3);  // 不解开Proxy
    try {
        session.get(User.class, 100L);  // 得到Proxy,命中数据库尝试解开Proxy,由于ID不存在因此抛出异常
        Assert.fail("ID不存在所以会出错,不会执行本条");
    } catch (ObjectNotFoundException ex) {

    }

    // 清空缓存
    session.clear();

    // 验证缓存为空的情况下get是否为Proxy
    User user6 = (User)session.get(User.class, 1L);  // 命中数据库,直接将组装完成的User实体进入缓存
    Assert.assertTrue(!(user6 instanceof HibernateProxy));

    // 验证get从缓存中取出对象
    User user7 = (User)session.get(User.class, 1L);
    Assert.assertTrue(!(user7 instanceof HibernateProxy)); // 缓存中是真实的User对象,get取出的就是真实的User对象

    // 验证load是否从一级缓存取数据
    User user8 = (User)session.load(User.class, 1L);
    Assert.assertTrue(!(user8 instanceof HibernateProxy));  // 缓存中是真实的User对象,load取出的也是真实的User对象

    tx.commit();
    session.close();
}

 

相信注释已经足够详细了,打开hibernate.show_sql,总共命中三次数据库(执行SQL),分别在高亮的三行处,其余的全是从缓存中取数据。
而且值得注意的一点是,如果对象是从load加载到缓存中的,那么不论get还是load获取出来的都是一个Proxy,如果没有被解开过,那么get会尝试解开它;如果对象是从get加载到缓存中的,那么load和get取出来都会是真实的实体对象。也就是说,get和load都会从缓存中取出对象,且取出的对象总是保持其第一次加载时的状态(load为Proxy,get为真实对象)

以上代码是一级缓存的验证,想验证二级缓存只需要从Hibernate中开启二级缓存再次运行代码即可

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/simon_steve_sun/archive/2010/03/17/5387974.aspx

Hibernate.initialize(Obj)用法

 

 

      持久化时,有时需要动态的改变对象的加载,比如在编辑页面里面lazy=true,而在浏览页面lazy=false,这样可以在需要lazy的地方才进行控制。而配置文件中Lazy属性是全局控制的,如何处理呢?

当<class>元素或者<set>元素的lazy属性为true时,load() or get() or find()加载这些对象时,Hibernate不会马上产生任何select语句,只是产生一个Obj代理类实例,只有在session没有关闭的情况下运行Obj.getXxx()时才会执行select语句从数据库加载对象,如果没有运行任何Obj.getXxx()方法,而session已经关闭,Obj已成游离状态,此时再运行Obj.getXxx()方法,Hibernate就会抛出"Could not initialize proxy - the owning Session was closeed"的异常,是说Obj代理类实例无法被初始化。然而想在Session关闭之前不调用Obj.getXxx()方法而关闭Session之后又要用,此时只要在Session关闭之前调用Hibernate.initialize(Obj)或者Hibernate.initialize(Obj.getXxx())即可,net.sf.hibernate.Hibernate类的initialize()静态方法用于在Session范围内显示初始化代理类实例。


         在配置文件里面可以用lazy=true,在程序里面可以用强制加载的方法Hibernate.initialize(Object proxy) 方法强制加载这样就相当于动态改变为lazy=false。
         但在使用时需要注意的一点是:其中的proxy是持久对象的关联对象属性,比如A实体,你要把A的关联实体B也检出,则要写Hibernate.initialize(a.b)。

Hibernate中Session.get()方法和load()方法的详细比较 今天小编就为大家分享一篇关于Hibernate中Session.get()方法和load()方法的详细比较,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧 立即下载

相关推荐

ADAS系统架构与核心功能解析:从感知到执行的智能驾驶方案

高级驾驶员辅助系统(ADAS)是现代汽车智能化的核心技术,其本质是通过传感器融合、算法决策与车辆控制,构建一个“感知-决策-执行”的闭环系统。在技术原理上,ADAS依赖摄像头、毫米波雷达、激光雷达等多源传感器进行环境感知,并通过深度学习模型与融合算法(如卡尔曼滤波)构建精准的环境模型。其技术价值在于提供主动安全冗余与驾驶舒适性,核心应用场景包括自动紧急制动(AEB)、自适应巡航(ACC)及车道保持辅助(LKA)等。随着传感器成本下降与域控制器算力提升,ADAS正从高端配置向主流车型快速普及,并逐步向高阶导航

weixin_31062533的博客 414

Hibernate session get()和load()区别,及疑问

Hibernate  session.load() 和session.get() 都能获取对象,并且获取的对象是持久态。 但是二者有区别: 1、当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象。即:当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的...

qq_26817225的博客 523

【ZZULIOJ】郑州轻工业大学oj题解整合

写在前面 关于ZZULIOJ题解 学习编程,想要巩固无非就是刷题或者做项目,然后因为我大一开始是刷郑轻的题目,就想着自己整合一下自己写的题目。既是复习也是笔记吧。 题解(内有题目描述) 1000 整数a+b 1001 植树问题 1002 简单多项式求值 1003 两个整数的四则运算 1004 三位数的数位分离 1005 整数幂 1006 求等差数列的和 1007 鸡兔同笼 1008 美元和人民币 1009 求平均分 1010 求圆的周长和面积 1011 圆柱体表面积 1012 求绝对值 1013 求两点间

蒟蒻乱写的博客 29万+

Hibernate中Session的get和load

hibernate中Session接口提供的get()和load()方法都是用来获取一个实体对象,在使用方式和查询性能上有一些区别。测试版本:hibernate 4.2.0。 get Session接口提供了4个重载的get方法,分别通过“持久类+主键”和“全类名+主键”以及“锁选项”来获取实体对象。 public Object get(Class clazz, Serializable...

weixin_30352191的博客 346

FreeRtos——10、全局看门狗设计

RTOS 里的看门狗不只是为了证明 CPU 还在动,而是为了证明每个业务逻辑都在按预期的节奏“呼吸”。

qq_40170041的博客 897

利用CAT12做皮层指标的统计分析及可视化笔记记录

利用CAT12做皮层指标的统计分析及可视化 文章目录利用CAT12做皮层指标的统计分析及可视化前言一、统计步骤1.Basic Models2.Estimate Surface Models3.Results二、可视化1.t值可视化2.p值可视化 前言 本来没有打算做SBM的,因为自己是新手小白,许多操作都不太懂,但最后还是打算做一下,于是就从上周末开始将很久之前跑VBM得到的surf文件夹中的数据捡起来继续做皮层分析,因为之前看了一个博主的博客,关于如何做SBM已经讲得非常清楚了,但是在统计及可视化这里,我

weixin_52073820的博客 8094

Flask(12)- 操作 Session

前言 Session 详解:https://www.cnblogs.com/poloyy/p/12513247.html 这一节来瞧一瞧如何用 Flask 操作 Session 功能 list 提供操作 Session 的 4 项功能 页面路径功能 /set 在 Session 中存储一个名称为 ‘user’、值为 ‘tom’ 的变量 /get 获取 Session 中名称...

qq_33801641的博客 333

C#实战:从零搭建Vosk离线语音转文字系统

本文手把手教你用C#构建离线语音转文字系统,基于NAudio和Vosk实现全流程开发。首先介绍环境搭建,包括NuGet包安装和中文模型配置,强调16kHz单声道音频格式的关键性。接着详细解析音频预处理转换、Vosk模型初始化及识别过程的核心代码,提供多线程优化建议和实时识别扩展思路。文章包含80%以上代码注释,从常见问题排查到性能优化技巧,完整覆盖从"Hello World"到工业级部署的关键技术点,特别适合需要开发本地化语音识别应用的C#开发者。

墨夶的博客 752

session.proxies账密代理_代理IP的连接使用与Session请求头的设置

代理IP的连接使用与Session请求头的设置向迅联加速购买了代理IP服务的用户,很多时候会将代理IP配置到Pyhton上使用,那么我们就需要知道代理IP能够在Python里面起到什么作用,哪些地方是可以用到的。今天迅联加速就来介绍代理IP的使用以及设置session请求头的具体教程:1、代理IP请求,存于redis:# 请求ip代理连接,更新redis的代理ipdef proxy_redis()...

weixin_39639965的博客 1927

【电机应用控制】——直流有刷电机&驱动板/编码器介绍&PID算法&实操代码思路

声明:学习笔记来自正点原子B站教程,仅供学习交流!!玩具车、平衡车、无人机、印刷机、打印机、手机振动马达等电机即电动机(motor),也叫作马达,电能转化为机械能。按电源:直流、交流按用途:驱动用、控制用按运转速度:高速、低速、恒速、调速直流电机(有刷、无刷)、舵机、步进电机、伺服电机1、直流有刷电机(Brushed DC Motor,简称BDC)是内含电刷装置的将直流电能转化为机械能的电动机。例如四驱赛车四个马达操控方便、成本低、维护时换电刷即可;

weixin_51658186的博客 2万+

【Bug已解决】Request timed out / API Timeout — Claude Code 请求超时解决方案

方案适用场景推荐指数难度方案一:增加超时大任务处理⭐⭐⭐⭐⭐低方案二:切换 SonnetOpus 太慢⭐⭐⭐⭐⭐低方案三:缩小范围大代码库⭐⭐⭐⭐⭐低方案四:优化网络网络延迟高⭐⭐⭐⭐中方案五:减少 MCPMCP 超时⭐⭐⭐中方案六:流式响应长生成任务⭐⭐⭐低根本原因:请求超时最常见原因是请求体过大(35%)和 Opus 模型推理慢(25%),默认 60 秒超时阈值对大型任务不够最佳实践。

一键难忘的博客 5157

关于Hibernate里面session的crud方法解析

1.SessionFactory这个是工厂类,生产session的,就相当于JDBC里面的DriveMannager,第一种获取Session的方法Session session = SessionFactory.openSession();session就是用来数据库crud的,也就是update,delete,select,insert的,相当于JDBC的stateme...

weixin_34189116的博客 76

AI驱动的网络安全运维:智能化时代的安全保障

本项目旨在使用Python和AI技术构建一个智能化的网络安全运维系统,能够实时监测网络流量,检测潜在的安全威胁,并自动采取应对措施,从而提升网络安全管理的效率和准确性。具体内容包括:环境配置与依赖安装数据采集与预处理机器学习模型构建与训练实时威胁检测与响应实际应用案例通过本文的介绍,我们展示了如何使用Python和AI技术构建一个智能化的网络安全运维系统。

Echo_Wish 1290

hibernate session的get和load方法

在hibernate中如果要从数据库中得到一个对象,通常有两种方式,一种是通过session.get(),另一种是通过session.load方法,下面具体说一下这两种方法。 1、load方式加载 使用load方法来加载一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象。也就是说,当使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前的到的这个

pmaxyt 1798

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

hibernate中Session 常用方法解析

1,save()方法 将一个临时对象转变成持久化对象;  2,load()方法 VSget()方法 都是根据 OID 从数据库中加载一个持久化对象。  区别 1:假如数据库中不存在与 OID 对应的记录,Load()方法会抛出异常,而 get()方法返回 null;  区别 2:load 方法默认采用延迟加载策略,get 方法采用立即检索策略;  2,update()方法 将一个游离对象转...

qq_40135955的博客 912

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

对于session.getAttribute("user");不能用问题的解决办法

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); HttpSession session = request.getSession(); User user = (User) session.getAttri

年年のBlog 1万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Hibernate三种状态和Session常用的方法

我们知道Hibernate的核心就是对数据库的操作,里面的核心接口就是org.hibernate.Session接口。要想对数据库操作我们就要理清楚对象在整个操作中的所属的状态。 就像马士兵老师在视频中所说的,我们并不必死抠这些字眼,我们通过自己编写测试类就可以他们之间不同的区别。       session中常用的方法是save(),update(),saveOrUpdate()这些

Coder的不平凡 7179

Django使用session登录 获取用户user_id信息

print(request.session.get('user_id', None)) print(request.session.get('is_login', None))

热衷开源的Boy 3620

Hibernate之Session的方法get()与load()的区别

(一)Session:管理一个数据库的任务单元 (二)get()与load()的区别: 1、不存在对应记录时表现不一样,get()会直接报错,load()不会直接报错,只有在真正使用到对象的时候才会报错 2、load()返回的是代理对象,等到真正用到对象的内容时才会发出sql语句 3、get()直接从数据库加载,不会延迟。         @Test public void testL

qq30211478的博客 400

hibernate中session的get、load比较

get方法: 查询成功返回实体对象,失败返回null; 采用立即查询机制,一级缓存->二级缓存->sql; load方法: 查询成功返回实体对象,失败抛出异常; 采用延迟查询机制,先在一级/二级缓存中查询,没找到则创建代理对象,真正使用时才发起sql;

大狼哥的专栏 726

Hibernate Session get()vs load()的区别

Hibernate Session get()vs load()的区别 Hibernate Session提供了从数据库中获取数据的不同方法。其中两个是 -get()和load()。我们还可以在不同的情况下使用很多重载方法。 首先看两者get()并且load()看起来相似,因为它们都从数据库中获取数据,但它们之间几乎没有差别,让我们用一个简单的例子来看一下它们。 packa...

YunWisdom 421

could not initialize proxy - no Session

在SSH整合项目中出现了如下错误信息: org.hibernate.LazyInitializationException:could not initialize proxy - no Session org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitiali...

weixin_34376562的博客 1915
上一篇: Hibernate POJO为什么要实现Serializable接口
下一篇: HQL Criteria
jamespengo
博客等级 码龄16年 83粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值