hibernate Load 代码分析

一直以来都想好好研究下hibernate代码,每次都是看一小段有点理解过段时间回来有忘光了,所以这次做下记录,免得重复劳动.


发现hibernate的代码还是挺复杂的,比spring ,struts要复杂的多,所以就一段段看。


今天主要分析一下hibernate如何来更新数据做CURP操作。


先看看load 和 get


public Object load(String entityName, Serializable id) throws HibernateException {

LoadEvent event = new LoadEvent(id, entityName, false, this);

boolean success = false;

try {

fireLoad( event, LoadEventListener.LOAD );

if ( event.getResult() == null ) {

getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );

}

success = true;

return event.getResult();

}

finally {

afterOperation(success);

}

}


get:

public Object get(String entityName, Serializable id) throws HibernateException {
LoadEvent event = new LoadEvent(id, entityName, false, this);
boolean success = false;
try {
fireLoad(event, LoadEventListener.GET);
success = true;
return event.getResult();
}
finally {
afterOperation(success);
}
}


对比这两个的代码发现只有

 if ( event.getResult() == null ) {

getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );

}


差别,其余都几乎一样,这行也没起多大作用, 仔细看发现调用fireLoad时的第2个参数不一样一个是LoadEventListener.GET, LoadEventListener.LOAD

跟踪

public static final LoadType GET = new LoadType("GET")
.setAllowNulls(true)
.setAllowProxyCreation(false)
.setCheckDeleted(true)
.setNakedEntityReturned(false);

public static final LoadType LOAD = new LoadType("LOAD")
.setAllowNulls(false)
.setAllowProxyCreation(true)
.setCheckDeleted(true)
.setNakedEntityReturned(false);


这里看名字就可以看出get允许为null, load不允许, 另外setAllowProxyCreation 值不一样,其他都一样。


下面看下fireLoad方法:

private void fireLoad(LoadEvent event, LoadType loadType) {
errorIfClosed();
checkTransactionSynchStatus();
LoadEventListener[] loadEventListener = listeners.getLoadEventListeners();
for ( int i = 0; i < loadEventListener.length; i++ ) {
loadEventListener[i].onLoad(event, loadType);
}
}


这里是对LoadEvent进行处理,调用已经注册好的LoadEventListener 去处理这个onLoad事件

这里的LoadEventListener的实现类是DefaultLoadEventListener

要弄明白hibernate是怎么获得一个数据的,就要看onLoad 方法了

/**
* Handle the given load event.
*
* @param event The load event to be handled.
* @throws HibernateException
*/
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException {

final SessionImplementor source = event.getSession();

EntityPersister persister;
         //获得当前pojo 的 EntityPersister
if ( event.getInstanceToLoad() != null ) {
persister = source.getEntityPersister( null, event.getInstanceToLoad() ); //the load() which takes an entity does not pass an entityName
event.setEntityClassName( event.getInstanceToLoad().getClass().getName() );
}
else {
persister = source.getFactory().getEntityPersister( event.getEntityClassName() );
}

if ( persister == null ) {
throw new HibernateException(
"Unable to locate persister: " +
event.getEntityClassName()
);
}

final Class idClass = persister.getIdentifierType().getReturnedClass();
if ( persister.getIdentifierType().isComponentType() && EntityMode.DOM4J == event.getSession().getEntityMode() ) {
// skip this check for composite-ids relating to dom4j entity-mode;
// alternatively, we could add a check to make sure the incoming id value is
// an instance of Element...
}
else {
if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {
// we may have the kooky jpa requirement of allowing find-by-id where
// "id" is the "simple pk value" of a dependent objects parent. This
// is part of its generally goofy "derived identity" "feature"
if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
final EmbeddedComponentType dependentIdType =
(EmbeddedComponentType) persister.getEntityMetamodel().getIdentifierProperty().getType();
if ( dependentIdType.getSubtypes().length == 1 ) {
final Type singleSubType = dependentIdType.getSubtypes()[0];
if ( singleSubType.isEntityType() ) {
final EntityType dependentParentType = (EntityType) singleSubType;
final Type dependentParentIdType = dependentParentType.getIdentifierOrUniqueKeyType( source.getFactory() );
if ( dependentParentIdType.getReturnedClass().isInstance( event.getEntityId() ) ) {
// yep that's what we have...
loadByDerivedIdentitySimplePkValue(
event,
loadType,
persister,
dependentIdType,
source.getFactory().getEntityPersister( dependentParentType.getAssociatedEntityName() )
);
return;
}
}
}
}
throw new TypeMismatchException(
"Provided id of the wrong type for class " + persister.getEntityName() + ". Expected: " + idClass + ", got " + event.getEntityId().getClass()
);
}
}

EntityKey keyToLoad = new EntityKey( event.getEntityId(), persister, source.getEntityMode() );

try {
if ( loadType.isNakedEntityReturned() ) {
//do not return a proxy!
//(this option indicates we are initializing a proxy)
event.setResult( load(event, persister, keyToLoad, loadType) );
}
else {
//return a proxy if appropriate
if ( event.getLockMode() == LockMode.NONE ) {
event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) );
}
else {
event.setResult( lockAndLoad(event, persister, keyToLoad, loadType, source) );
}
}
}
catch(HibernateException e) {
log.info("Error performing load command", e);
throw e;
}
}




这里最后调用event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) ); 在默认无锁的情况下。

protected Object proxyOrLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {

if ( log.isTraceEnabled() ) {
log.trace(
"loading entity: " +
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}

if ( !persister.hasProxy() ) {
// this class has no proxies (so do a shortcut)
return load(event, persister, keyToLoad, options);
}
else {
final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();

// look for a proxy
Object proxy = persistenceContext.getProxy(keyToLoad);
if ( proxy != null ) {
return returnNarrowedProxy( event, persister, keyToLoad, options, persistenceContext, proxy );
}
else {
if ( options.isAllowProxyCreation() ) {
return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
}
else {
// return a newly loaded object
return load(event, persister, keyToLoad, options);
}
}

}
}



protected Object doLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {

if ( log.isTraceEnabled() ) {
log.trace(
"attempting to resolve: " +
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}

Object entity = loadFromSessionCache( event, keyToLoad, options );
if ( entity == REMOVED_ENTITY_MARKER ) {
log.debug( "load request found matching entity in context, but it is scheduled for removal; returning null" );
return null;
}
if ( entity == INCONSISTENT_RTN_CLASS_MARKER ) {
log.debug( "load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null" );
return null;
}
if ( entity != null ) {
if ( log.isTraceEnabled() ) {
log.trace(
"resolved object in session cache: " +
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
return entity;
}

entity = loadFromSecondLevelCache(event, persister, options);
if ( entity != null ) {
if ( log.isTraceEnabled() ) {
log.trace(
"resolved object in second-level cache: " +
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
return entity;
}

if ( log.isTraceEnabled() ) {
log.trace(
"object not resolved in any cache: " +
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}

return loadFromDatasource(event, persister, keyToLoad, options);
}



	private Object createProxyIfNecessary(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext) {
Object existing = persistenceContext.getEntity( keyToLoad );
if ( existing != null ) {
// return existing object or initialized proxy (unless deleted)
log.trace( "entity found in session cache" );
if ( options.isCheckDeleted() ) {
EntityEntry entry = persistenceContext.getEntry( existing );
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return null;
}
}
return existing;
}
else {
log.trace( "creating new proxy for entity" );
// return new uninitialized proxy
Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad);
persistenceContext.addProxy(keyToLoad, proxy);
return proxy;
}
}


hibernate 是采用事件回调模式去处理一个数据库的操作,通过load返回的实际上是一个proxy的对象, 在debug模式下查看这个proxy 对象得到

[b]"proxy"= Event_$$_javassist_0 (id=78)[/b]

看来这个好像是用javassist类库来增强过的pojo对象,load返回的就是这个对象了。

如果是get方法将会调用 doLoad 方法去获得

if ( options.isAllowProxyCreation() ) {
return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
}
else {
// return a newly loaded object
return load(event, persister, keyToLoad, options);
}


get 方式的时候 isAllowProxyCreation 值为false的,参看前面的代码

doLoad方法先去sessionCache然后再去secondCache去查找 给定对象,如果没有的话就调用

return loadFromDatasource(event, persister, keyToLoad, options);

从数据库找,代码:

/**
* Performs the process of loading an entity from the configured
* underlying datasource.
*
* @param event The load event
* @param persister The persister for the entity being requested for load
* @param keyToLoad The EntityKey representing the entity to be loaded.
* @param options The load options.
* @return The object loaded from the datasource, or null if not found.
*/
protected Object loadFromDatasource(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {
final SessionImplementor source = event.getSession();
Object entity = persister.load(
event.getEntityId(),
event.getInstanceToLoad(),
event.getLockOptions(),
source
);

if ( event.isAssociationFetch() && source.getFactory().getStatistics().isStatisticsEnabled() ) {
source.getFactory().getStatisticsImplementor().fetchEntity( event.getEntityClassName() );
}

return entity;
}



这里最终调用 AbstractEntityPersister.load 方法,代码:

public Object load(Serializable id, Object optionalObject, LockOptions lockOptions, SessionImplementor session)
throws HibernateException {

if ( log.isTraceEnabled() ) {
log.trace(
"Fetching entity: " +
MessageHelper.infoString( this, id, getFactory() )
);
}

final UniqueEntityLoader loader = getAppropriateLoader(lockOptions, session );
return loader.load( id, optionalObject, session, lockOptions );
}


这里会得到一个合适的loader, 我测试的时候得到的是 org.hibernate.loader.entity.EntityLoader
它继承与 AbstractEntityLoader

public Object load(Serializable id, Object optionalObject, SessionImplementor session, LockOptions lockOptions) {
return load( session, id, optionalObject, id, lockOptions );
}

protected Object load(
SessionImplementor session,
Object id,
Object optionalObject,
Serializable optionalId,
LockOptions lockOptions) {

List list = loadEntity(
session,
id,
uniqueKeyType,
optionalObject,
entityName,
optionalId,
persister,
lockOptions
);

if ( list.size()==1 ) {
return list.get(0);
}
else if ( list.size()==0 ) {
return null;
}
else {
if ( getCollectionOwners()!=null ) {
return list.get(0);
}
else {
throw new HibernateException(
"More than one row with the given identifier was found: " +
id +
", for class: " +
persister.getEntityName()
);
}
}

}


调用 loadEntity 方法, 代码:


protected final List loadEntity(
final SessionImplementor session,
final Object id,
final Type identifierType,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalIdentifier,
final EntityPersister persister,
LockOptions lockOptions) throws HibernateException {

if ( log.isDebugEnabled() ) {
log.debug(
"loading entity: " +
MessageHelper.infoString( persister, id, identifierType, getFactory() )
);
}

List result;
try {
QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( new Type[] { identifierType } );
qp.setPositionalParameterValues( new Object[] { id } );
qp.setOptionalObject( optionalObject );
qp.setOptionalEntityName( optionalEntityName );
qp.setOptionalId( optionalIdentifier );
qp.setLockOptions( lockOptions );
result = doQueryAndInitializeNonLazyCollections( session, qp, false );
}
catch ( SQLException sqle ) {
final Loadable[] persisters = getEntityPersisters();
throw JDBCExceptionHelper.convert(
factory.getSQLExceptionConverter(),
sqle,
"could not load an entity: " +
MessageHelper.infoString( persisters[persisters.length-1], id, identifierType, getFactory() ),
getSQLString()
);
}

log.debug("done entity load");

return result;

}


继续追踪,跟到方法

private List doQuery(
final SessionImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws SQLException, HibernateException {

final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = hasMaxRows( selection ) ?
selection.getMaxRows().intValue() :
Integer.MAX_VALUE;

final int entitySpan = getEntityPersisters().length;

final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );

// would be great to move all this below here into another method that could also be used
// from the new scrolling stuff.
//
// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
// that I could do the control breaking at the means to know when to stop

final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final List results = new ArrayList();

try {

handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );

EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row

if ( log.isTraceEnabled() ) log.trace( "processing result set" );

int count;
for ( count = 0; count < maxRows && rs.next(); count++ ) {

if ( log.isTraceEnabled() ) log.debug("result set row: " + count);

Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies
);
results.add( result );

if ( createSubselects ) {
subselectResultKeys.add(keys);
keys = new EntityKey[entitySpan]; //can't reuse in this case
}

}

if ( log.isTraceEnabled() ) {
log.trace( "done processing result set (" + count + " rows)" );
}

}
finally {
session.getBatcher().closeQueryStatement( st, rs );
}

initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) );

if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );

return results; //getResultList(results);

}

这里进行最终的数据库读取,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值