`

从源码层面来看load与get的区别(五): Hibernate源码研究碎得(9)

阅读更多

上一篇花了很长时间梳理了下SessionImplementor接口与Hibernate里其它关键类和接口的关系并画出类图,最后得出"集万千宠爱于一身的SessionImpl"标题.本篇将接着往下走,下面先看第二句 EntityPersister persister;

声明了一个变量persister.(写到这有两种选择,一是像对SessionImplementor一样对这个EntityPersister接口好好研究一番,这样的话研究的很细,不过一个突出的问题就是由get方法牵连出很多点,分散精力;另一选择是把这个EntityPersister放在当前DefaultLoadEventListener类里结合它的具体应用来有个初步的认识. ... 现在尝试第二种选择,由于对SessionImplementor的研究是用第一种方法来展开的,看看这第二种选择有什么优缺点,再进一步来看如何与第一种结合起来以达到优势互补.)

有了上面的研究策略,这样把DefaultLoadEventListener类里的第62行至第76行拿出来做为一个意群(借用高考语文阅读训练中的一个术语)整体研究.

先看persister这个变量的声明方式,这里在第62行并没有对其赋值,结合项目中的一些经验,这样的声明是有一定的风险的,处理不好就报NullPointerException了.

先说说项目中遇到的类似情况及是怎么报异常的:
这样的一个异常容易发生在MVC端,

假设在C端有如下的处理逻辑:
 Result result;

 if(parameterConditionOne){
  result = conditionOneProgram.getResult();
 }else if (parameterConditionTwo){
  result = conditionTwoProgram.getResult();
 }
 .................
 result.setXXX();   // --- A

看上面的代码,若两个条件都不满足的话,在A处就会报NullPointerException,原因就在于分析情况时没有考虑全就造成现在这样的漏网之鱼.若在else if后再加一个else分枝呢?这样也是有值得注意的地方的,是否在非parameterConditionOne非parameterConditionTwo时就一定是else里的情况呢?

看Hibernate是怎么处理类似的麻烦事的:
在源码里71至76行的判断及异常处理.也就是说在经过if...else的赋值后再看这个persister是否这空,若为空就抛出一个HibernateException,这样把NullPointerException这样很唐突很底层的异常转为更为specific地异常.

现在看了Hibernate这里的处理方法后,佩服Hibernate的同时,也感觉到自己的成长,这样也就更加坚定了自己研究源码.

上面这段让我想起了自己项目中的一个Bug,现在再回到Hibernate的处理逻辑中.
第一个分支,即:event.getInstanceToLoad() != null 也就是说若event在初始化时传入并设置了instanceToLoad属性,这当然不是get方法时的调用情况了,BTW:Session接口中的load(Object object, Serializable id)方法就是这样的情况:在初始化LoadEvent事例时把load方法传入的Object对象再次传给LoadEvent的构造方法,从而就赋给了instanceToLoad属性.

若是这样的已初始化了instanceToLoad属性,persister的初始化就不同了,即通过source.getEntityPersister来返回,这样好像也能说的过去,毕竟那个instance已经在persistenceContext里存在了,这个instance也已经绑定了与之对应的EntityPersister了,也就不用再new一个EntityPersister的实现类对象了.在这里需要做的就是把event里的EntityClassName赋下值,现在的猜想是若传入了instanceToLoad就没有再传相应类的名字.这也很好理解,毕竟一个instanceToLoad本身就已经带了很丰富的内容.

source.getEntityPersiter()

与event.getInstanceToLoad() != null相反的是没有传入instanceToLoad对象,这种情况下我猜想是Hibernate在此时利用如下语句new出来一个与当前EntityClassName对应的EntityPersister实现类对象.
persister = source.getFactory().getEntityPersister( event.getEntityClassName());


追着源码看,并没有找到我猜想的那个new,那两种getEntityPersister有什么区别?也就是说若instanceToLoad不为null时的source.getEntityPersister与instanceToLoad为null时的source.getFactory().getEntityPersister两种有什么不同?这样就落在getFactory有什么用?

...............

从表面上来看是落在getFactory的作用上,但若往深入地看时发现,source.getEntityPersister实质上也是调用getFactory,而真正不同的是,这个方法中又调用了SessionImpl类里的guessEntityName方法,顾名思义,就是根据传入的Object对象来猜出这个Object在Hibernate里的Entity名字,不过还想往下问的是这样guess出来的名字与利用Object的反射得到的className有什么不同?毕竟LoadEvent里的getEntityClassName就是通过Class类的getName()方法获得的.这个问题先放这吧.

接着往下走,就是看ID是用什么类来表示的?是Long?是Integer?是String?并把这个类型与xxx.hbm.xml中的配置的类型做比较,若不符的话就抛出TypeMismatchException,我觉得这样的比较意义倒不是很大,或者说我不大理解为什么要这样比较?像一个Long型的id若用一个int型的值来表达时也不是不可以的吧?当然只要那个实际的值别超过int类型的范围,不过不理解归不理解,在使用时还是一定注意这个问题的.

这里还有一个问题:
 persister.getIdentifierType().isComponentType() && EntityMode.DOM4J == event.getSession().getEntityMode()
 怎么上面这个条件成立时就不用来比较了呢?当然若是componentType的话就没有明显的一个className了,这倒是一个原因,但这与EntityMode.DOM4J又有什么关系呢?这个问题还是只能先放这了.

 下面又有一个新类EntityKey,不禁要问这个类是干啥的?为什么叫EntityKey呢?这样这个onLoad方法在每次调用时都new出来一个这样的对象是不是很是浪费?好像是JVM在每new一个对象时很耗资源的.能不能像Spring所提倡的那样最好用单例?又是什么因素制约着不能用单例呢?带着这些问题看EntityKey这个类的源码.
 看这个类的源码发现与其它的类并没什么特殊的联系.自身除了三个方法外,也没有特别的.
 这三个方法分别为private的generateHashCode与访问修饰为默认的serialize还有一个static且返回值为Entity的deserialize方法.这个deserialize方法没什么可说的,它自身就是一个工厂方法,返回一个EntityKey对象.
 先看generateHashCode方法,这个方法也只是在EntityKey的构造方法中调用一次,对传入构造方法里的各个参数分别调用它们的hashCode方法并最终拼出一值赋给EntityKey的属性hashCode,这样也就能多多少少地了为什么叫key了.那这个key又具体怎么用呢?只能在它的具体应用中来看了.这让我想起了现在项目中通过字符串的方式拼出来的值作为自制缓存中key来使用了,为什么不用类的hasCode呢?那样的话显得的更专业.
 再看serialize这个方法,它将EntityKey里的属性通过writeObject方法写进传入的ObjectOutputStream参数中?为什么要这样呢?这个serialize方法在什么情况下调用?想达到什么效果?是要写入本地文件中吗?追着看了看没看出什么门道,就先放在这吧.
 
 从EntityKey返回到DefaultLoadEventListener类里的onLoad方法.下面将根据loadType是否为isNakedEntityReturned与LockMode是否为LockMode.NONE来调用不同的load方法,这里有三个不同的方法,依次是load,proxyOrLoad,lockAndLoad.这三个方法中除了第三个方法lockAndLoad多一个SessionImplementor型的参数外,都接收前面准备好的或onLoad传来的四个参数:event, persister, keyToLoad, loadType.

 大致看了下这三个方法,proxyOrLoad,lockAndLoad这两人都有视情况不同而调用load方法.这样就先研究这个load方法了.

 今天写了不少,虽说是有些乱.在下一篇中将重点看这个load方法.

2
1
分享到:
评论
3 楼 rmn190 2009-02-22  
rmn190 写道

1, "那两种getEntityPersister有什么区别?"   现在感觉第一种方式包含在第二种里了, 我们做下的猜想: 第二种通过EntityClassName从那个factory中以Map的key方式取出EntityPersister, 也就是说比第一种多了个map的get()操作.2, "新类EntityKey,不禁要问这个类是干啥的?"    回过头来看, 觉得这个类是当把load来的东西放到缓存时的Key.



说是放到缓存时的Key不够确切, 应该说是放到当前Session缓存中的Key, 与二级缓存没关系, 想想也是二级缓存是Hibernate的调用者选择配置的, Hibernate自身怎么回"干涉"二级缓存中的事呢?
2 楼 rmn190 2009-02-21  
1, "那两种getEntityPersister有什么区别?"
   现在感觉第一种方式包含在第二种里了, 我们做下的猜想: 第二种通过EntityClassName从那个factory中以Map的key方式取出EntityPersister, 也就是说比第一种多了个map的get()操作.

2, "新类EntityKey,不禁要问这个类是干啥的?"
    回过头来看, 觉得这个类是当把load来的东西放到缓存时的Key.

1 楼 rmn190 2009-02-21  
"若为空就抛出一个HibernateException,这样把NullPointerException这样很唐突很底层的异常转为更为specific地异常":

    不仅仅是一个自己项目中那样的NullPointerException问题,这时还包括在那种情况下都没有得到实例的情况,hibernate已经通过if... else把漏网之鱼堵住了,本质上跟自己项目中的情况大不一样.

相关推荐

    hibernate 三种 查询 方式 load与get的区别

    本篇文章将详细解析Hibernate中的三种主要查询方式——HQL(Hibernate Query Language)、Criteria API和Query API,并着重讨论`load()`与`get()`方法的区别。 一、HQL查询 Hibernate Query Language(HQL)是...

    hibernate中get和load方法的区别

    在Java的持久化框架Hibernate中,`get`和`load`方法都是用于从数据库中获取对象,但它们之间存在一些重要的区别。理解这些差异对于优化应用程序的性能和避免潜在问题至关重要。 首先,`get`方法是直接从数据库中...

    Hibernate的get和load方法的区别

    在Hibernate源码中,`get`方法直接调用了`sessionFactory`的`load`方法,但是传递了一个额外的参数`LockMode.NONE`,这表明它不希望获取任何锁定。而`load`方法允许设置不同的锁模式,以支持并发控制。 在实际开发...

    Hibernate查询 load与get的区别及其它查询测试

    `load`和`get`方法是Hibernate中用于检索实体的两种主要方式,它们都是从Session接口中调用,但有明显的区别和各自的适用场景。 1. `load`方法: - `load`方法主要用于根据主键加载对象,它返回一个代理对象,而...

    hibernate-3.2源码包

    5. **Session接口**:是Hibernate的核心接口,负责对象的持久化操作,如保存(save())、更新(update())、删除(delete())以及查询(load(), get())等。 6. **Transaction管理**:Hibernate支持JTA(Java ...

    hibernate3.6.1源码

    Hibernate 是一个著名的开源Java对象关系映射(ORM)框架,它极大地简化了数据库与Java应用程序之间的交互。在本文中,我们将深入探讨Hibernate 3.6.1版本的源码,了解其内部工作原理以及关键组件的功能。 源码分析...

    hibernate5jar包以及源码

    2. **持久化模型**:源码中可以看到,Hibernate通过注解或XML配置文件来定义Java类为持久化实体,实现了对象与数据库表之间的映射。 3. **缓存机制**:Hibernate支持二级缓存,源码中可以深入理解其工作流程,包括...

    hibernate入门学习笔记+源码

    **hibernate入门学习笔记+源码** **一、Hibernate简介** Hibernate是一个开源的对象关系映射(ORM)框架,它简化了Java应用与数据库之间的交互。通过提供对象化的数据访问方式,Hibernate消除了传统JDBC代码中的...

    hibernate-3.2源码

    4. 加载(Load/Get):根据主键从数据库中获取对象,返回持久化状态的对象。 六、查询语言 1. HQL:Hibernate查询语言,类似SQL但面向对象,可以方便地进行对象间的关联查询。 2. Criteria API:提供更灵活的查询...

    精通hibernate源码ch2

    在深入探讨Hibernate源码之前,我们首先需要理解什么是对象持久化技术。对象持久化是将内存中的对象状态保存到持久存储介质(如数据库)中,以便在后续的程序运行中可以恢复这些对象的状态。它解决了应用程序中的...

    Hibernate源码解析(一)

    《Hibernate源码解析(一)》 在Java开发领域,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地运用该工具,还能提升对Java编程和...

    hibernate源码的学习

    在Hibernate源码的学习过程中,我们可以深入理解ORM的工作原理,提高我们的Java开发技能,并且能够更好地优化数据库操作。 一、Hibernate核心组件 1. Configuration:配置对象,负责读取hibernate.cfg.xml文件,...

    hibernate_first_new项目源码

    【hibernate_first_new项目源码】是一个关于Hibernate框架学习的项目,主要涵盖了对Hibernate常用接口的详细讲解和实例应用。Hibernate是一个强大的Java持久层框架,它为开发者提供了对象关系映射(ORM)功能,使得...

    Hibernate基础学习源码

    本资源“Hibernate基础学习源码”提供了五个不同阶段的学习示例,分别命名为Hibernate_01至Hibernate_04以及Hibernate_M2M,涵盖了Hibernate的基本概念、配置、实体映射、CRUD操作以及多对多关系的处理。 1. **...

    Hibernate电子版及源码

    《Hibernate电子版及源码》资源集合是一份珍贵的学习材料,专为那些渴望深入了解Java持久化框架Hibernate的开发者准备。Hibernate作为一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作...

    传智播客李勇hibernate源码1-20课

    传智播客李勇hibernate源码1-20课,目录如下:01_hibernate介绍与动手入门体验;02_hibernate入门案例的细节分析; 03_hibernate入门案例的代码优化; 04_Session接口及get|load|persist方法 05_实体对象的三种状态...

    HIbernate3.2中文说明及其源码

    这份资料包含的中文说明将帮助开发者更好地理解和使用Hibernate3.2,而源码则提供了深入学习和研究的宝贵资源。 1. Hibernate ORM概述: Hibernate是一种将Java对象与关系数据库进行映射的技术,它通过提供一种...

    hibernate-3.2 源码

    Hibernate是一个开源的对象关系映射(ORM)框架,它允许Java开发者将数据库操作转换为对象级别的操作,从而简化了数据访问层的开发。在 Hibernate 3.2 版本中,这个框架已经相当成熟,提供了丰富的功能和性能优化。...

    hibernate入门框架源码

    2. **实体类和映射文件**:在Hibernate中,我们创建Java类来表示数据库中的表,通过Hibernate的XML映射文件(或注解)定义这些类与数据库表的对应关系。 3. **SessionFactory和Session**:SessionFactory是...

    java hibernate上课源码6

    Java Hibernate 是一个强大的持久化框架,它简化了Java应用程序与关系数据库之间的交互。这个"java hibernate 上课源码6"应该包含了一系列示例代码,用于教授如何在实际项目中应用Hibernate。通过深入理解这些源码,...

Global site tag (gtag.js) - Google Analytics