`
guzizai2007
  • 浏览: 361686 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Hibernate缓存

 
阅读更多

1、缓存定义:

1)、缓存介于应用程序和物理数据源之间,缓存中的数据是对数据库中数据的复制,其作用就是降低应用程序对数据源的访问频次,提高应用的运行性能。Hibernate在读取数据的时候,先会在缓存中查询,如果缓存中有相应数据(缓存命中),则直接用里面的数据,避免发送sql到数据库查询的性能消耗。
2)、关键字:缓存----数据库数据复制----放在内存中-----查询时先查缓存----命中直接返回,减少查询消耗。

2、Hibernate缓存分类:

1)、第一种Session缓存:Hibernate内置的缓存机制,不能卸载。该缓存的生命周期依赖于Session对象,Session对象创建则缓存开始,Sessio对象关闭缓存也就随之结束。一般一个Session对应一个事务,所以Session级别的缓存也称为事务缓存,而一个Session对应一个单独的线程,各个线程的Session是不一样的,所以Session缓存也不能共享。
2)、第二种SessionFactory缓存:使用第三方插件,可插拔,又称为应用缓存。这种缓存可以被应用范围内的所有Session共享,这种Session的生命周期随依赖应用的生命周期。
3)、关键字:
Session缓存----Hibernate内置----依赖Session生命周期----线程(Session)独有-----不能共享
SessionFactory------第三方提供------应用范围内------所有Session共享

3、Session缓存(同一个Session中):

1)、同一个Session两次get方法查询同一个对象:
---------------------------------------------------------------------------------------
//发出查询语句
User user1 = (User) session.get(User.class, 1L);
//不会发出查询语句,直接在缓存中查询
User user2 = (User) session.get(User.class, 1L);
//验证两次取出的是否是同一个对象
System.out.println("是否是同一对象:"+(user==user2));

结果打印信息(只有一条查询语句):
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
是否是同一对象:true
---------------------------------------------------------------------------------------
2)、同一个Session两次Iterator查询同一个对象:
---------------------------------------------------------------------------------------
		//这里会发出查表id的sql语句
		Iterator<User> itr1 = session.createQuery("from User").iterate();
		
		while(itr1.hasNext()){
			User user = itr1.next();
			//这里会根据id查询具体User对象,然后保存在缓存中
			System.out.println(user.getUsername()+"--->>>>>>");
		}
		System.out.println("第一次遍历结束");
		
		//发出查表id的sql语句
		Iterator<User> itr2 = session.createQuery("from User").iterate();
		
		while(itr2.hasNext()){
			User user = itr2.next();
			//会先根据id到缓存中找是否有这个User对象,有则直接使用,没有就要数据库中查找
			System.out.println(user.getUsername()+"--->>>>>>");
		}
		System.out.println("第二次遍历结束");

结果打印信息:

Hibernate: select user0_.user_id as col_0_0_ from core_user user0_
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼0--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼1--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼2--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼3--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼4--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼5--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼6--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼7--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼8--->>>>>>
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
傻逼9--->>>>>>
第一次遍历结束
Hibernate: select user0_.user_id as col_0_0_ from core_user user0_
傻逼0--->>>>>>
傻逼1--->>>>>>
傻逼2--->>>>>>
傻逼3--->>>>>>
傻逼4--->>>>>>
傻逼5--->>>>>>
傻逼6--->>>>>>
傻逼7--->>>>>>
傻逼8--->>>>>>
傻逼9--->>>>>>
第二次遍历结束
---------------------------------------------------------------------------------------
3)、第一次iterator查询会发出N+1条sql语句,第一句先查出所有id,然后根据id查询所有实体对象,并保持在Session缓存中,第二次iterator查询先查所有id,然后拿着这些id到Session缓存中查询是否有对应的实体对象,结果是有,所以就不发送sql到数据库了。
4)、Session缓存不缓存属性,只缓存对象。

4、save操作:

1)、save一个对象,但不提交事务:
---------------------------------------------------------------------------------------
//开启一个事务
		session = HibernateSessionFactory.getSession();
		tc = session.beginTransaction();
		
		User user = new User();
		user.setAge(99);
		user.setUsername("傻逼99");
		
		//保存对象  此时只分配了一个id给它,还没同步到数据库中  但会把该对象保存在缓存中
		Serializable id =session.save(user);
		
		User user2 = (User) session.get(User.class, id);
		System.out.println(user2.getUsername());

打印信息:
Hibernate: select hibernate_sequence.nextval from dual
傻逼99
---------------------------------------------------------------------------------------
提交事务后:
//开启一个事务
		session = HibernateSessionFactory.getSession();
		tc = session.beginTransaction();
		
		User user = new User();
		user.setAge(99);
		user.setUsername("傻逼99");
		
		//保存对象  此时只分配了一个id给它,还没同步到数据库中  但会把该对象保存在缓存中
		Serializable id =session.save(user);
		
		User user2 = (User) session.get(User.class, id);
		System.out.println(user2.getUsername());
		
		tc.commit();

打印信息:
Hibernate: select hibernate_sequence.nextval from dual
傻逼99
Hibernate: insert into core_user (user_name, age, user_id) values (?, ?, ?)

---------------------------------------------------------------------------------------
2)、执行save操作会先把对象保存在缓存中,当事务提交或者session.flush时,才会同步到数据库中,所以如果大批量save对象,每save一个对象就放到缓存中,对象数量足够大时,内存肯定溢出,所以可以每保存一定数量的对象就手动清理下缓存,例如:
if (i % 20 == 0) {
		    //数据持久化,同步到数据库
		    session.flush();
		    //清除缓存的内容
		    session.clear();
		}

5、SessionFactory二级缓存:

1)、使用第三方缓存EHCache,项目中添加encache相关jar包,增加一个ehcache.xml文件放在类路径下:
-----------------------------------------------------------------------------------
<!-- 默认缓存配置 -->
    <defaultCache
    	<!-- 缓存里可以放10000个对象 -->
        maxElementsInMemory="10000"
        <!-- 过不过期,如果是true就是永远不过期 -->
        eternal="false"
        <!-- 一个对象被访问后多长时间还没有访问就失效(120秒还没有再次访问就失效) -->
        timeToIdleSeconds="120"
        <!-- 对象存活时间(120秒),如果设置永不过期,这个就没有必要设了 -->
        timeToLiveSeconds="120"
        <!-- 溢出的问题,如果设成true,缓存里超过10000个对象就保存到磁盘里 -->
        overflowToDisk="true"
        />
-----------------------------------------------------------------------------------
也可以单独配置:
<!-- 针对某个对象单独配置 -->    
    <cache name="com.sxit.cache.User"
        maxElementsInMemory="100"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
-----------------------------------------------------------------------------------
2)、然后在hibernate.cfg.xml中添加:
<!-- 缓存提供商 -->
    	<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
 <!-- 启用二级缓存 默认是true 可不写 -->
    	<property name="cache.use_second_level_cache">true</property>

<!-- 这里可以配置那些实体类需要用到二级缓存  也可在实体类的hbm文件中配置 -->
    	<class-cache usage="read-only" class="com.sxit.cache.User"/>
3)、useage属性表示缓存策略,一般选择read-only,如果这个对象放在缓存中,则不能被修改,如果修改则会报错,所以说,如果是经常要修改的对象,就不用放在缓存中了。使用read-only策略效率好,因为不能改缓存。但是可能会出现脏数据的问题,这个问题解决方法只能依赖缓存的超时,比如上面我们设置了超时为120秒,120后就可以对缓存里对象进行修改,而在120秒之内访问这个对象可能会查询脏数据的问题,因为我们修改对象后数据库里改变了,而缓存却不能改变,这样造成数据不同步,也就是脏数据的问题。
4)、第二种缓存策略read-write,当持久对象发生变化,缓存里就会跟着变化,数据库中也改变了。这种方式需要加解锁,效率要比第一种慢。

6、二级缓存的使用:

1)、两个Session,开启二级缓存查询同一个对象:
//开启一个新事务  发起两次相同查询
		session = HibernateSessionFactory.getSession();
		tc = session.beginTransaction();
		
		user = (User) session.get(User.class, 1L);
		System.out.println(user);
		tc.commit();
		HibernateSessionFactory.closeSession();
		
		session = HibernateSessionFactory.getSession();
		tc = session.beginTransaction();
		
		user = (User) session.get(User.class, 1L);
		System.out.println(user);
		tc.commit();
		HibernateSessionFactory.closeSession();

打印信息:
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
com.sxit.cache.User@1fe571f
com.sxit.cache.User@12bf892
2)、两个Session,不开二级缓存查询相同对象:
//开启一个新事务  发起两次相同查询
		session = HibernateSessionFactory.getSession();
		tc = session.beginTransaction();
		
		user = (User) session.get(User.class, 1L);
		System.out.println(user);
		tc.commit();
		HibernateSessionFactory.closeSession();
		
		session = HibernateSessionFactory.getSession();
		tc = session.beginTransaction();
		
		user = (User) session.get(User.class, 1L);
		System.out.println(user);
		tc.commit();
		HibernateSessionFactory.closeSession();

打印信息:
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
com.sxit.cache.User@1fe571f
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
com.sxit.cache.User@12bf892
3)、一级、二级缓存之间的交互:
//禁止一二级缓存交互 这样的话对象只保存在Session缓存中,不会保存到二级缓存中
		session.setCacheMode(CacheMode.IGNORE);

打印信息:
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
com.sxit.cache.User@1fe571f
Hibernate: select user0_.user_id as user1_0_0_, user0_.user_name as user2_0_0_, user0_.age as age0_0_ from core_user user0_ where user0_.user_id=?
com.sxit.cache.User@12bf892
4)、二级缓存不能存放普通属性

7、查询缓存:

1)、一级缓存和二级缓存都只是存放实体对象的,如果查询实体对象的普通属性的数据,只能放到查询缓存里,查询缓存还存放查询实体对象的id。
2)、查询缓存的生命周期不确定,当它关联的表发生修改,查询缓存的生命周期就结束。这里表的修改指的是通过hibernate修改,并不是通过数据库客户端软件登陆到数据库上修改。
3)、hibernate的查询缓存默认是关闭的,如果要使用就要到hibernate.cfg.xml文件里配置:
<property name="hibernate.cache.use_query_cache">true</property>
并且必须在程序中手动启用查询缓存,在query接口中的setCacheable(true)方法来启用。
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    深入理解Hibernate缓存

    ### 深入理解Hibernate缓存 #### 一、Hibernate缓存概述 Hibernate作为一款流行的Java持久层框架,为开发者提供了高效且灵活的数据访问能力。其中,缓存机制是Hibernate性能优化的重要组成部分之一。理解Hibernate...

    Hibernate缓存深入详解 from ITEye

    **Hibernate缓存深入详解** 在Java企业级应用开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。然而,随着应用规模的扩大,数据访问性能成为了一个不可忽视的问题。这时,...

    Hibernate缓存技术研究

    ### Hibernate缓存技术研究 #### 一、引言 Hibernate是一种强大的对象-关系映射(Object-Relational Mapping,简称ORM)工具,主要用于Java环境下的应用程序。它能够将应用程序中的对象模型映射到关系型数据库的表...

    Hibernate缓存.doc

    Hibernate缓存.docHibernate缓存.doc

    Java Hibernate缓存深入详解

    Java Hibernate缓存深入详解

    hibernate缓存

    ### Hibernate缓存机制及优化策略 #### 一、概述 Hibernate作为一款优秀的对象关系映射(ORM)框架,在Java开发领域被广泛应用于数据库操作。它提供了丰富的缓存机制来提高应用性能并降低数据库访问压力。本文将...

    Hibernate缓存与spring事务详解

    **标题:“Hibernate缓存与Spring事务详解”** 在IT领域,尤其是Java开发中,Hibernate作为一款流行的ORM(对象关系映射)框架,极大地简化了数据库操作。而Spring框架则以其全面的功能,包括依赖注入、AOP(面向切...

    hibernate缓存机制

    Hibernate缓存机制是提高应用程序性能的关键技术之一,它通过存储数据副本减少对物理数据库的访问。缓存可以分为两层:第一级缓存和第二级缓存。 **第一级缓存**是内置在Session中的,它是不可卸载的,也称为...

    hibernate缓存深入详解.

    关于hibernate缓存的一个ppt课件,60+幻灯片,有需要的可以看一下

    Hibernate缓存深入详解

    【Hibernate缓存深入详解】 在Java的持久化框架Hibernate中,缓存机制是提升系统性能的关键因素。它位于Hibernate应用和数据库之间,减少了对数据库的直接访问,从而提高了应用程序的运行速度。缓存中存储的是...

    Hibernate缓存详解

    **Hibernate缓存详解** 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。为了提高数据访问性能,Hibernate引入了缓存机制,它可以减少对数据库的直接访问,从而提升应用的...

    Hibernate缓存,性能优化

    本文将深入探讨Hibernate缓存的原理、类型及其对性能优化的影响。 ### Hibernate缓存原理 Hibernate缓存主要分为一级缓存和二级缓存。一级缓存,也称为会话缓存(Session Cache),是默认启用的,由Hibernate自动...

    hibernate缓存和事务

    Hibernate 是一个流行的对象关系映射(ORM)框架,它允许Java...通过理解Hibernate缓存和事务管理,以及如何有效地执行查询,开发者可以创建高效、健壮的Java应用程序,降低与数据库交互的复杂性,同时提升系统性能。

    Hibernate教程25_Hibernate缓存

    **标题解析:** "Hibernate教程25_Hibernate缓存" 这个标题表明了我们要讨论的是关于Hibernate框架的第25个教程,重点是它的缓存机制。Hibernate是一个流行的Java对象关系映射(ORM)框架,它允许开发者用面向对象的...

    Hibernate缓存管理.doc

    【Hibernate缓存管理】是数据库持久化框架Hibernate中优化性能的关键技术。缓存的主要目的是减少对数据库的直接访问,提高应用程序的运行效率。缓存的数据是数据库中数据的副本,存在于内存或硬盘中,便于快速读取。...

    hibernate缓存ehcache用法

    这篇博客文章“hibernate缓存ehcache用法”可能详细介绍了如何在Hibernate中配置和使用Ehcache。 首先,我们需要理解什么是缓存。缓存是一种存储技术,用于临时保存经常访问的数据,以减少对主存储器(如数据库)的...

    hibernate 缓存

    【Hibernate缓存详解】 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。其缓存机制是提升系统性能的关键所在。本篇将深入探讨Hibernate的缓存机制,包括一级缓存和二级...

Global site tag (gtag.js) - Google Analytics