从源码层面来看load与get的区别(二): Hibernate源码研究碎得(6)
从源码层面来看load与get的区别(二): Hibernate源码研究碎得(5)
接着上一篇问题的引入,本篇中我们先从Session里我们很熟悉的get(Class entityClass, Serializable id)起步.小菜这用的例子是Hibernate里自带那个,
?程序的入口为下面的Java语句:
?person = (Person) session.get(Person.class, 1L);
?在DB中已事先插入下面一条记录:
?PERSON_id?age?firstname? lastname
??1??????????????? 0???????? Foozy?? Beary
下面将记录下用Eclipse里用Debug跟踪时发现的很值得关注的Breakpoints:
进入Session的实现类SessionImpl后,将调用方法
?get(String entityName, Serializable id)?? ----(1)
其中entityName就是Person.class.getName()的值.
进入方法(1)后,将通过LoadEvent的构造方法
?LoadEvent(Serializable entityId, String entityClassName, boolean isAssociationFetch, EventSource source)? ??----(2)
创建一个LoadEvent对象,构造方法中传入的参数依次为,尖括号中的为通过Eclipse的Debug时Variables看到的实参值.
?id<1>,entityName<events.Person>,isAssociationFetch<false>,EventSource<SessionImpl的实例引用,也就是this>
前两个参数无需说明,先看下形参isAssociationFetch对其的赋值为false,我猜想,通过这个false告诉下面代码块这个Persion类在此次get时以notAssociationFetch来进行(这时有点疑问:若想从这样get得到的Instance里获取那些与之关联的数据会怎样呢?是Hibernate会自动再到DB中去取?当然这样的再取是很不efficient的,毕竟从DB取数时最忌讳一次能获得的而要来回地折腾多次.或在某种特定的情况下--比如说想查找下这个Person对象的所有信息,想一次性地获得与Person对象关联的所有数据又该怎么来做?用get好像就不行了吧?load行吗?通过Query接口以HQL的形式?对了,在HQL里是可以写fetch这个准关键字的....看Java Persistence with Hibernate这本书时,看到了如下的一句说明:
?All entity associations and collections aren't retrieved.If you access any proxied association or uninitialized collection, a second SELECT? is executed to retrieve the data on demand.
?也就是说Hibernate会给那些关联的entity创建一个proxy,在默认情况下,当访问这些proxy里的数据时,Hibernate再去DB中取去相应的数据.
?那是不是可以通过在xxx.hbm.xml中改变那个默认fetch策略的方式来达到利用一个简单的get方法就可以获得相关的数据呢?好像不行吧,因为到现在的创建LoadEvent对象为止,还没有看到任何读取配置信息的操作..........
).
?最后一个参数EventSource没什么可说的,SessionImpl类实现了EventSource接口,不过这里顺便说下的是Hibernate大量应用了Event-Action模式.
?在构造方法(2)里又调用构造方法
?private LoadEvent(Serializable entityId,String entityClassName,Object instanceToLoad,LockMode lockMode,boolean isAssociationFetch,EventSource source)? ---(3)
与(2)处的构造方法相比,(3)处的构造方法又多了两个形参
?Object:instanceToLoad与LockMode:lockMode
与这两个形参对应的实参都是null.这个null本身没什么可考虑的,在此值得再进一步联想的是这个instanceToLoad,既然已是一个instance了,还需要再load吗?难道说是通过这个可以达到refresh的功能?进一步看源码一探虚实.带着这个问题,利用Eclipse的"Open Call Hierarchy"功能顺藤摸瓜地看到Session中的一个load方法就是利用了这个instanceToLoad的特性,这个load是没有返回值的,这样也就暗合了基refresh的功能.
?LockMode在此没什么多说的,先从Hibernate源码中把LockMode里所定义的6种限制级别列举一下,它们依次是:
?NONE,READ,UPGRADE,UPGRADE_NOWAIT,WRITE,FORCE.
BYW,从这个类里可以很好地看出Java里枚举类型的雏形.在这个LoadEvent类里(更准确地说是在当前的这个private的构造方法里.),若loadMode为null时,就将其设为了值为LockMode.NONE的DEFAULT_LOCK_MODE模式.
?
?(BTW,从LoadEvent类的构造方法的设计上也多少看出了点以后自己有用的东西:用private来修饰那个参数最多的构造方法,其余的构造方法视具体的调用而通过this结合null的方式调用那个private的.)
?这样这个LoadEvent就创建出来了.
这些都是前期工作,下一篇中将看实质一点的方法
?fireLoad(event, LoadEventListener.GET);