`
duantonghai
  • 浏览: 20345 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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 对象得到

"proxy"= Event_$$_javassist_0  (id=78)

看来这个好像是用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);

	}

这里进行最终的数据库读取,
分享到:
评论

相关推荐

    Hibernate源码解析(一)

    - 错误排查:当遇到问题时,源码分析能更准确地定位问题所在,提高解决问题的效率。 - 自定义扩展:熟悉源码后,我们可以根据需求自定义拦截器、事件监听器等,实现特定功能。 总结来说,Hibernate源码解析是一个...

    Hibernate源代码

    **二、Hibernate 源码分析** 1. **SessionFactory**:SessionFactory 是线程安全的,它是 Hibernate 的核心组件,负责创建 Session 实例。源码中,SessionFactory 的创建过程涉及了配置信息的读取、缓存策略的设置...

    hibernate-3.2源码包

    通过深入学习和分析 Hibernate 3.2 的源代码,开发者可以更全面地理解其内部工作原理,从而更好地利用这个强大的工具,提高开发效率,减少数据库操作的复杂度。源码包中的内容包括了核心库、示例项目、文档等,为...

    hibernate3.6.1源码

    源码分析: 1. **对象关系映射(ORM)**:Hibernate的核心功能是实现ORM,它将Java类映射到数据库表,对象的属性对应于表的列。在Hibernate 3.6.1中,这一映射主要通过`hibernate.cfg.xml`配置文件和`.hbm.xml`映射...

    hibernate框架配置源码

    **hibernate框架配置源码详解** Hibernate是一个强大的对象关系映射(ORM)框架,它为Java开发者提供了在关系数据库上操作对象的...记住,实践是最好的老师,动手操作并结合源码解析,才能真正掌握Hibernate的魅力。

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

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

    hibernate5jar包以及源码

    4. **查询语言**:HQL(Hibernate Query Language)和 Criteria API 是Hibernate提供的两种查询方式,源码解析能帮助理解它们的实现原理。 5. **事件和监听器**:源码揭示了如何利用事件监听器进行持久化过程的定制...

    hibernate入门源代码

    让我们逐步解析这些源代码,了解Hibernate的基本使用方法。 ### Hibernate ORM 概念 Hibernate 提供了一种在Java应用中管理和操作数据库对象的抽象层。它通过XML配置文件或注解来定义对象与数据库表之间的映射关系...

    精通hibernate源码ch2

    6. Hibernate源码解析: - SessionImpl:实际的Session实现,包含对数据库的CRUD操作。 - PersistentClass:表示映射元数据的类,用于解析.hbm.xml文件。 - QueryImpl:HQL查询的实现,解析HQL语句并生成SQL。 -...

    hibernate-3.2 源码

    通过阅读和分析Hibernate 3.2的源码,我们可以深入了解ORM框架的设计理念,学习如何优化数据库操作,以及如何在实际项目中灵活运用Hibernate提供的各种功能。同时,这也有助于我们掌握Java反射、代理、元数据解析等...

    hibernate源码的学习

    总结,学习Hibernate源码有助于我们理解ORM的底层实现,掌握对象关系映射的精髓,从而在实际项目中更好地利用Hibernate提升开发效率和代码质量。通过对"hibernate-one2many"的分析,我们可以深入研究和实践一对一和...

    hibernate入门学习笔记+源码

    **六、源码分析** `hibernate_test`、`hibernate_test3`、`hibernate_test2`这些文件可能包含了示例项目的源代码,包括配置文件、实体类、DAO层操作以及测试用例。通过分析这些源码,你可以更好地理解Hibernate在...

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

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

    Hibernat一级缓存(源码)

    源码分析: Hibernate 的一级缓存主要由 `org.hibernate.engine.spi.SessionImplementor` 接口和它的实现类 `org.hibernate.internal.SessionImpl` 完成。在 `SessionImpl` 类中,一级缓存被称为“实体管理器”...

    Hibernate实例代码

    - **读取(Read)**: 使用`get()`或`load()`方法获取对象,`createQuery()`或`createCriteria()`执行HQL(Hibernate Query Language)查询。 - **更新(Update)**: 对对象属性进行修改后,调用`update()`方法更新...

    北京圣思园Hibernate源代码

    北京圣思园提供的Hibernate源代码是学习和研究Hibernate内部机制的重要资源,本文将基于这一资源,对Hibernate的核心概念、工作原理及其源码进行深入解析。 一、Hibernate概述 Hibernate是一个开放源码的对象关系...

    java hibernate上课源码6

    这个"java hibernate 上课源码6"很可能包含了以上这些知识点的实例,通过分析和运行这些代码,你可以更好地理解和掌握Hibernate的使用。每个文件可能对应一个特定的主题,例如配置文件的设置、CRUD操作的实现、关联...

    hibernate最简单源代码

    【hibernate最简单源代码】是一个用于学习和理解Hibernate框架基本用法的代码示例。Hibernate是一个流行的Java ORM(对象关系映射)框架,它允许开发者以面向对象的方式操作数据库,极大地简化了数据访问层的开发...

    hibernate3.5源代码

    源代码中,`Session` 实现了各种持久化操作,如 `save()`, `load()`, `update()`, `delete()`。 通过研究 Hibernate 3.5 的源代码,开发者可以深入理解 ORM 的工作原理,学习如何优化数据访问性能,以及如何利用 ...

    Hibernate原理解析

    阅读和分析源代码是深入理解Hibernate原理的有效途径。 总之,Hibernate通过ORM简化了数据库操作,提升了开发效率,而对其原理的深入理解有助于我们更好地应用和优化这个强大的工具。通过不断的实践和探索,我们...

Global site tag (gtag.js) - Google Analytics