一直以来都想好好研究下hibernate代码,每次都是看一小段有点理解过段时间回来有忘光了,所以这次做下记录,免得重复劳动.
发现hibernate的代码还是挺复杂的,比spring ,struts要复杂的多,所以就一段段看。
今天主要分析一下hibernate如何来更新数据做CURP操作。
先看看load 和 get
get:
对比这两个的代码发现只有
差别,其余都几乎一样,这行也没起多大作用, 仔细看发现调用fireLoad时的第2个参数不一样一个是LoadEventListener.GET, LoadEventListener.LOAD
跟踪
这里看名字就可以看出get允许为null, load不允许, 另外setAllowProxyCreation 值不一样,其他都一样。
下面看下fireLoad方法:
这里是对LoadEvent进行处理,调用已经注册好的LoadEventListener 去处理这个onLoad事件
这里的LoadEventListener的实现类是DefaultLoadEventListener
要弄明白hibernate是怎么获得一个数据的,就要看onLoad 方法了
这里最后调用event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) ); 在默认无锁的情况下。
hibernate 是采用事件回调模式去处理一个数据库的操作,通过load返回的实际上是一个proxy的对象, 在debug模式下查看这个proxy 对象得到
[b]"proxy"= Event_$$_javassist_0 (id=78)[/b]
看来这个好像是用javassist类库来增强过的pojo对象,load返回的就是这个对象了。
如果是get方法将会调用 doLoad 方法去获得
get 方式的时候 isAllowProxyCreation 值为false的,参看前面的代码
doLoad方法先去sessionCache然后再去secondCache去查找 给定对象,如果没有的话就调用
return loadFromDatasource(event, persister, keyToLoad, options);
从数据库找,代码:
这里最终调用 AbstractEntityPersister.load 方法,代码:
这里会得到一个合适的loader, 我测试的时候得到的是 org.hibernate.loader.entity.EntityLoader
它继承与 AbstractEntityLoader
调用 loadEntity 方法, 代码:
继续追踪,跟到方法
这里进行最终的数据库读取,
发现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);
}
这里进行最终的数据库读取,