--get:
sessionImpl调用IdentifierLoadAccessImpl.load(id);在这个方法中,sessionFactoryImpl.getEntityPersister从entityPersisters map取entity的mapping信息,放到LoadEvent, 然后sessionImpl.fireLoad(event);
fireLoad从listeners列表找到onload的listener并调用其onload.
这个listener是DefaultLoadEventListener。参数event和loadType. get将调用load-->onLoad取entity。看onLoad的说明:
Coordinates the efforts to load a given entity. First, an attempt is made to load the entity from the session-level cache. If not found there, an attempt is made to locate it in second-level cache. Lastly, an attempt is made to load it directly from the datasource.
onLoad方法里有清晰的结构,loadFromXXX. 我们看loadFromDatasource,其调用了SingleTableEntitypersister.onLoad,这个方法在其父类里。它调用EntityLoader.load(在其父类里).
--stackTrace:
sessionImpl-->DefaultLoadEventListener-->persister-->EntityLoader
最接近DB的一层,从Loader.doQuery()开始。
注意其getSQLString()在子类中实现,这里是OuterJoinLoader。在prepareQueryStatement中将sql打印到log,在getResultSet中终于调到熟悉的st.executeQuery();
load的策略主要在listener里实现,与DB交互的细节在persister&loader中。
--20140422: get与load的区别:fireLoad的参数不同:LoadEventListener.LOAD与GET,看其定义,分别是setAllowProxyCreation(false)与true,在loadListener.proxyOrLoad中据此判断proxy还是load.
--后记:
persister有singletable, joined and union。loader有EntityLoader, QueryLoader,CriterialLoader等,queryLoader用ast(基于antlr)分析和生成sql。EntityLoader和CriterialLoader从JoinWalker取得sql.(参见AbstractEntityJoinWalker)
-------saveOrUpdate的过程:----------
类似get,可以分析saveOrUpdate的过程。sessionImpl fireSaveOrUpdate,调用一系列listeners, 这里是DefaultUpdateEventListener.但是基本没有实质性的操作。那,数据什么时候存到DB去的呢?
session.flush()的时候。flush也有相应的DefaultFlushEventListener。
flush()很关键,相反,saveOrUpdate甚至可以不要。如果session.get(User.class,2);即使不调用saveOrUpdate,user对像也会在flush的时候与DB同步。
这里要注意的一点,是transaction. autocommit属性默认为false(也不建议改为true), 则没有commit操作,数据不会存到DB。
--flush()的过程:
flush()主要有两个过程(对entity及connections):flush和perform。flush将有改变的操作放到session的actionQueue,perform一个个执行(通过上边提到过的persister)。
--query:
以sessionImpl为中心,queryImpl处理一下params,又调回到sessionImpl.list()。
list()调用HQLQueryPlan.performList()-->QueryTranslator.list()-->QueryLoader.list()。对比entityLoader,这里没有listener,persister,对应的是QueryPlan和QueryTranslator.
在loader.list()中可以看到查询缓存的作用:决定了是调用listUsingQueryCache还是listIgnoreQueryCache-->doList()统计一下-->doQuery()将rs转为list-->executeQueryStatement()加filter加limit加locks-->getResultSet()。
常见问题:
1,get与load的区别:load调gegReference以LOAD参数调eventListener.onLoad。这个参数在defaultLoadEventListener.proxyOrLoad中有反映。
2,query.list()与iterate()与scroll的区别:在HQLQueryPlan中perform不同的方法,在QueryTranslator中调用不同的方法-->queryLoader。
3,集合类映射:注解可以加在成员上或get上但不能混用。user一对多orderitem,则orderitem中加JoinColumn user_id。
4,fetchType:只影响get,load,queryLoader不是一个outerJoinLoader,criteria是。关于left outer join, 参见AbstractEntityJoinWalker.initStatementString()的associations。关键是取得怎样的loader。来看abstractEntitypersister.associations()。
sessionImpl调用IdentifierLoadAccessImpl.load(id);在这个方法中,sessionFactoryImpl.getEntityPersister从entityPersisters map取entity的mapping信息,放到LoadEvent, 然后sessionImpl.fireLoad(event);
fireLoad从listeners列表找到onload的listener并调用其onload.
这个listener是DefaultLoadEventListener。参数event和loadType. get将调用load-->onLoad取entity。看onLoad的说明:
Coordinates the efforts to load a given entity. First, an attempt is made to load the entity from the session-level cache. If not found there, an attempt is made to locate it in second-level cache. Lastly, an attempt is made to load it directly from the datasource.
onLoad方法里有清晰的结构,loadFromXXX. 我们看loadFromDatasource,其调用了SingleTableEntitypersister.onLoad,这个方法在其父类里。它调用EntityLoader.load(在其父类里).
--stackTrace:
sessionImpl-->DefaultLoadEventListener-->persister-->EntityLoader
最接近DB的一层,从Loader.doQuery()开始。
注意其getSQLString()在子类中实现,这里是OuterJoinLoader。在prepareQueryStatement中将sql打印到log,在getResultSet中终于调到熟悉的st.executeQuery();
load的策略主要在listener里实现,与DB交互的细节在persister&loader中。
--20140422: get与load的区别:fireLoad的参数不同:LoadEventListener.LOAD与GET,看其定义,分别是setAllowProxyCreation(false)与true,在loadListener.proxyOrLoad中据此判断proxy还是load.
--后记:
persister有singletable, joined and union。loader有EntityLoader, QueryLoader,CriterialLoader等,queryLoader用ast(基于antlr)分析和生成sql。EntityLoader和CriterialLoader从JoinWalker取得sql.(参见AbstractEntityJoinWalker)
-------saveOrUpdate的过程:----------
类似get,可以分析saveOrUpdate的过程。sessionImpl fireSaveOrUpdate,调用一系列listeners, 这里是DefaultUpdateEventListener.但是基本没有实质性的操作。那,数据什么时候存到DB去的呢?
session.flush()的时候。flush也有相应的DefaultFlushEventListener。
flush()很关键,相反,saveOrUpdate甚至可以不要。如果session.get(User.class,2);即使不调用saveOrUpdate,user对像也会在flush的时候与DB同步。
这里要注意的一点,是transaction. autocommit属性默认为false(也不建议改为true), 则没有commit操作,数据不会存到DB。
--flush()的过程:
flush()主要有两个过程(对entity及connections):flush和perform。flush将有改变的操作放到session的actionQueue,perform一个个执行(通过上边提到过的persister)。
--query:
以sessionImpl为中心,queryImpl处理一下params,又调回到sessionImpl.list()。
list()调用HQLQueryPlan.performList()-->QueryTranslator.list()-->QueryLoader.list()。对比entityLoader,这里没有listener,persister,对应的是QueryPlan和QueryTranslator.
在loader.list()中可以看到查询缓存的作用:决定了是调用listUsingQueryCache还是listIgnoreQueryCache-->doList()统计一下-->doQuery()将rs转为list-->executeQueryStatement()加filter加limit加locks-->getResultSet()。
常见问题:
1,get与load的区别:load调gegReference以LOAD参数调eventListener.onLoad。这个参数在defaultLoadEventListener.proxyOrLoad中有反映。
2,query.list()与iterate()与scroll的区别:在HQLQueryPlan中perform不同的方法,在QueryTranslator中调用不同的方法-->queryLoader。
3,集合类映射:注解可以加在成员上或get上但不能混用。user一对多orderitem,则orderitem中加JoinColumn user_id。
4,fetchType:只影响get,load,queryLoader不是一个outerJoinLoader,criteria是。关于left outer join, 参见AbstractEntityJoinWalker.initStatementString()的associations。关键是取得怎样的loader。来看abstractEntitypersister.associations()。