`
sslaowan
  • 浏览: 380410 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Hibernate3.6 缓存

 
阅读更多

 

一级缓存

    一级缓存和get,load,save,iterator都有关系。

    使用HQL,SQL进行属性查询时,跟一级缓存无关。

    一级缓存的生命周期是事务

 

二级缓存

        Hibernate的二级缓存本质上就是存储对象实例,对象的id作为key,使用二级缓存就是按照id去加载。

        注意查询缓存的配置方法。网上很多文章都是试验说这个用不了缓存那个用不了的,就下结论说用不了,实际上多是配置有问题。我是结合了源代码和实验来看的。

 

查询缓存

    如果想使用query cache我们需要配置 hibernate.cfg.xml文件:


<class ......>

   <property nam="hibernate,cache.use_query_cache">True</property>

</class>

 
   在编码当中使用:Query.setQueryCache(true);即可。

 

 

Get和Load

session的load和get方法最底层都是调用org.hibernate.event.def.DefaultLoadEventListene 的dooad方法。

(题外话:load(entityame,id)方法如果找不到对象,则抛出异常,load(entityObject,id)实际上是重新加载对象,而get方法如果找不到则会返回null)

 

结论

 

1 通过下面代码可以看到先加从一级缓存加载,再从二级缓存加载,如果都没有则从数据库加载。  

2 Get和Load都跟查询缓存无关

 

但是Get和Load是不同的,Get方法会调用:

 

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);
	}





 

  而Load如果使用延迟加载的化,那么则会生成proxy。

  这是由于LoadType的不同:

 

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);
 

  其中AllowProxyCreation在Get中设置为false,Load设置为POST。

所以对于Get而言,对延迟加载无效,直接查询,然后按顺序从Session缓存,二级缓存,数据库中读取;Load,则使用延迟加载。


  List和Find

find底层调用的就是list。

1 当开启查询缓存时,二级缓存才能派上用场,过程如下:

 1) 第一次执行sql时,会从数据库中获得数据,然后将数据放入到二级缓存中,将sql语句,查询参数(位置,类型),以及最大行数信息做成key放到查询缓存中,并缓存这个key对应的所有entity的id

 2) 当第二次执行这个sql时,发现查询缓存里有,则调用load方法,按查询缓存里的id一个一个去load对象。可见,如果只开了查询缓存没开二级缓存就惨了,上面已经说了,load会先到一二级缓存里去找,没有再到数据库找,如果没开二级缓存或者被flush掉了,意味着每个entity都要到数据库里去找,速度更慢

 

2 如果没有开启查询缓存,而开启了二级缓存呢?那么每次查询都会从数据库中获得,然后flush二级缓存。

3 如果都没开启,那么就只是查。

 

由上面还可以推出load和get都可以获得list之后带来的二级缓存中的对象。

 

 

Hibernate官方文档 写道
大多数查询并不会从缓存中获得什么好处,所以默认查询是不进行缓存的。要进行缓存,调用 Query.setCacheable(true)。这个调用会让查询在执行时去从缓存中查找结果,或者把结果集放到缓存去。
如果你要对查询缓存的失效政策进行精确的控制,你必须调用Query.setCacheRegion()来为每个查询指定一个命名的缓存区域。

 

 

List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
    .setEntity("blogger", blogger)
    .setMaxResults(15)
    .setCacheable(true)
    .setCacheRegion("frontpages")
    .list();

 

  QBC 与QBE

  底层调用来session的list方法。

 

  代码调用的过程如下:

  • org.hibernate.impl.SessionImpl

 

List





 





list





(CriteriaImpl





 criteria





)

   根据criteria获得entity的名字或class名字创建一个implementors字符串数组,然后为每个implementor创建一个CriteriaLoader,然后循环loader调用list方法。

  • org.hibernate.loader.Loader
    loader的list方法会对cache(这里指查询缓存)作出判断,走连个不同的分支:
   
		final boolean cacheable = factory.getSettings().isQueryCacheEnabled() &&

		queryParameters.isCacheable();

		if ( cacheable ) {

			return listUsingQueryCache( session, queryParameters, querySpaces, resultTypes );
		}
		else {
			return listIgnoreQueryCache( session, queryParameters );
 

		}
   如果是listIgnoreQueryCahce这个分支 ,那么接下来就是走了doList,doList里面调用了doQuery,如下:







doQuery





    这个方法里面会根据传入的QueryParemeter,和session构建jdbc的PreparedStatement,然后获得jdbc ResultSet,再迭代ResultSet获得hibernate的Row,放入到list返回。

   在调用getResultList从返回的list里获得结果返回。

   整个过程即:

 

	private List  listIgnoreQueryCache(SessionImplementor session, QueryParameters queryParameters) { 

		return getResultList( doList( session, queryParameters ), queryParameters.getResultTransformer() ); 

	}
 

 

    如果是走listUsingQueryCache这个分支 ,则先调用

getResultFromQueryCache




  

  如果获得的result为空,则跟上一种情况相同,执行doList,不过会把结果放入到queryCache中,然后调用调用getResultList从返回的list里获得结果返回。

 

   刚才说的Loader是个基类,它有两个子类,一个是CustomLoader,一个是BasicLoader,后者还有三个实现子类:org.hibernate.hql.classic.QueryTranslatorImpl, org.hibernate.loader.hql.QueryLoader, org.hibernate.loader.OuterJoinLoader,

,最后这个还有四个子类。

   对于缓存这块,它们都没有做更多事情。

 

查询缓存

 读取查询缓存是调用来QueryCahce这个接口,hibernate自己的标准实现类是org.hibernate.cache.StandardQueryCache

 

Iterator

    这个方法会先用一个sql把所有的id都查出来,然后一个一个load,这就可以利用二级缓存。
    可以配合

 

  1. session.evict(youObject);  
  2. sessionFactory.evice(YouObject.class, youObject.getId());  

 

   清除session缓存和二级缓存。

关于使用Hibernate API修改数据库

    一级缓存

 

     在save时首先会到session缓存(也就是一级缓存)中去看看这个对象是不是已经是持久态,如果是就不调用insert方法,否则insert之后放到session缓存中。

       二级缓存

    那么跟二级缓存的关系呢?

    简单的说,如果使用主键删除修改增加,比如save,update方法,那么就会更新缓存,改了哪个更新哪个

   如果使用HQL,那就通通干掉了。(网上说法不一,也有说不会更新二级缓存,我也没看到源代码,自己做实验把)

     今天看了一下debug信息,使用saveOrUpdate方法,其不会更新二级缓存,而是在load时才会将结果放入到二级缓存中:

DEBUG adding entity to second-level cache:

       查询缓存

 

          只有有更改,查询缓存全被干掉。也有地说是跟这个表有关的查询缓存才会被干掉,这个还得自己试验一下,也没跟到相应的代码。

 

   不通过Hibernate API更新数据库对缓存的影响

 

   自然Hibernate不知到数据库变了,那么就只能通过下面的缓存API 搞定来

   对于二级缓存就跟介绍Iterator时说的那样清除缓存。

 

    对于查询缓存,就需要执行QueryCache的clear方法才能避免脏数据,这时就会清除所有的缓存,也就是那堆id,如果想精细控制,就要用CacheRegion。实际上调用sessionFactory里的evictQueries。

 

 

参考资料

虽然是参考资料,但是参考资料上说的也不都对,所以有冲突的地方,以我的为准

Hibernate缓存原理  http://myoraclex.blog.51cto.com/2288027/413183

 

Hibernate CRUD,帖子中有很多错误  http://developer.51cto.com/art/200909/154150.htm

 

Hiberante 查询缓存的使用条件 http://www.blogjava.net/os586/archive/2006/07/25/60019.html

 

  总结了一下各种缓存 http://www.iteye.com/topic/249465

  这个帖子对CRUD的缓存情况说的比较好http://elf8848.iteye.com/blog/805351

 

有关Get,Load的讲解,细微之处还需进一步验证http://fantasyyong.iteye.com/blog/146685

分享到:
评论

相关推荐

    Hibernate3.6

    **Hibernate 3.6 框架详解** Hibernate 是一个广泛使用的开源对象关系映射(ORM)框架,它为Java开发者提供了便捷的方式来处理数据库操作。在 Hibernate 3.6 版本中,这个框架继续强化了其在简化数据库访问、提高...

    hibernate 3.6 中文 chm

    《Hibernate 3.6 中文 CHM》是一个针对Hibernate 3.6版本的详细使用指南,旨在帮助开发者理解和掌握这个强大的对象关系映射(ORM)框架。Hibernate是Java开发中的一个重要工具,它允许程序员以面向对象的方式处理...

    hibernate3.6

    5. **第二级缓存**:为提高性能,Hibernate 3.6引入了第二级缓存机制。它允许数据在多个会话间共享,减少对数据库的访问。`@Cacheable`注解可标记为可缓存的实体,而`@Cache`注解用于配置缓存策略。 6. ** Criteria...

    hibernate3.6.jar

    `hibernate3.6.jar` 是Hibernate 3.6版本的核心库,包含了实现ORM功能所需的类和接口。 在这个版本中,Hibernate 提供了以下主要功能和知识点: 1. **对象关系映射(ORM)**:Hibernate 提供了一种将Java对象与...

    hibernate3.6框架中文文档

    **Hibernate 3.6 框架中文文档** Hibernate 是一个强大的对象关系映射(ORM)框架,它允许Java开发者将数据库操作与业务逻辑层解耦,极大地简化了数据库编程。此文档是Hibernate 3.6版本的官方中文翻译,为开发者...

    hibernate3.6参考文档中英文

    标题"hibernate3.6参考文档中英文"表明这是一个关于Hibernate 3.6版本的综合参考资料,包含中文和英文两个版本。Hibernate是一个流行的Java ORM(对象关系映射)框架,它使得Java开发者可以更加便捷地在数据库上操作...

    hibernate3.6所有包

    在这个“hibernate3.6所有包”压缩文件中,包含了Hibernate 3.6版本的所有核心组件和依赖库。这个版本在当时是一个重要的里程碑,因为它引入了许多改进和新特性。 1. **Hibernate核心**:这是Hibernate框架的基础,...

    Hibernate 3.6 Final Source Code

    《深入探索Hibernate 3.6源码:核心与实践》 Hibernate 3.6作为一款广泛应用的Java对象关系映射(ORM)框架,其源代码是开发者深入理解ORM机制、优化数据库操作的重要参考资料。该源码包“hibernate-core-3.6.0....

    我见过的最好的最详细的hibernate3.6.X学习资料(汤阳光)

    【hibernate3.6.X】是一个流行的Java持久化框架,它实现了ORM(对象关系映射)技术,使得开发者可以通过面向对象的方式处理数据库操作,从而降低了数据库编程的复杂性。在传统的三层架构中,hibernate常被用作数据...

    基于hibernate3.6的jpa例子

    在这个文件中,我们可以定义数据源、指定Hibernate为JPA提供者、设置缓存策略等。例如: ```xml &lt;provider&gt;org.hibernate.ejb.HibernatePersistence ... ``` 现在,我们可以通过EntityManager接口来...

    hibernate 3.6 api 和帮助文档 打包一起

    这个压缩包“Hibernate 3.6 API 和帮助文档 打包一起”包含了关于Hibernate 3.6版本的重要资源,对于学习和使用该版本的Hibernate非常有帮助。 API文档是开发人员理解任何库或框架的关键,Hibernate 3.6的API文档...

    Hibernate3.6中文文档

    《Hibernate 3.6中文文档》是一份详尽的指南,专为中文用户提供了关于Hibernate 3.6版本的深入理解和应用。Hibernate是Java平台上的一款流行的对象关系映射(ORM)框架,它允许开发者用面向对象的方式来处理数据库...

    Hibernate3.6中文文档.rar

    这个“Hibernate3.6中文文档”是针对Hibernate 3.6版本的详细指南,旨在帮助中文用户更好地理解和使用Hibernate框架。 ### 一、Hibernate概述 Hibernate简化了Java应用程序与数据库之间的交互,通过将对象模型与...

    hibernate3.6中文帮助文档

    7. **缓存机制**:Hibernate支持第一级缓存(Session级别的)和第二级缓存(SessionFactory级别的),可以显著提高数据访问效率。 8. **关联映射**:包括一对一、一对多、多对一、多对多等各种关系映射,用于处理...

    SSH整合的jar包之hibernate3.6

    在本场景中,我们关注的是SSH整合中的Hibernate3.6版本,它是一个强大的对象关系映射(ORM)框架,能够将数据库操作与业务逻辑解耦。以下是关于SSH整合与Hibernate3.6的详细知识: 1. **SSH框架简介** - Spring:...

    hibernate3.6中文手册

    《Hibernate 3.6中文手册》是一份详细且全面的指南,旨在帮助开发者理解和掌握Hibernate这一流行的Java对象关系映射(ORM)框架。该手册由Hibernate的官方网站提供,旨在为中文用户提供了方便的学习资料,使其能更好...

    Spring3.2和Hibernate3.6整合源码和jar包

    Spring3.2与Hibernate3.6的整合是Java开发中常见的技术栈组合,主要用于构建企业级的后端应用。这两个框架的结合可以帮助开发者更高效地管理应用程序的依赖注入和持久化层,使得代码更加模块化,易于维护。下面将...

    Hibernate3.6所需核心包

    在这个“Hibernate3.6所需核心包”中,我们很显然是在讨论Hibernate 3.6版本的关键组件。 Hibernate 3.6是该框架的一个稳定版本,它包含了多项改进和新特性,以提升性能和易用性。以下是一些关键的知识点: 1. **...

Global site tag (gtag.js) - Google Analytics