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

hibernate入门(十)缓存

阅读更多

1. 模拟缓存并简要说明缓存实现原理

myhibernate 项目下新建一个包 com.asm.hibernate.test.cacheTest 来说明与缓存有关的问题。首先看下面的一个模拟缓存程序,主要代码如下:

package com.asm.hibernate.test.cacheTest;

public class CacheSimulate {

    static Map cache = new HashMap();

    public static void main(String[] args) {

       addUser ();

       // 第一次查询,会去连接数据库查询

       User u1 = getUser (1);

       // 第二次查询,直接从 Map cache 中取

       User u2 = getUser (1);

       // 第三次查询,同样从 cache 中直接取

       User u3 = getUser (1);

    }

 

    static User getUser( int id) {

       String key = User. class .getName() + id;

       User user = (User) cache .get(key);

       if (user != null )

           return user;

       user = getUserFromDB (id);

       cache .put(key, user);

       return user;

    }

 

    static void addUser() {

       省略代码,此方法的作用主要是向数据库添加一条记录,以方便查询操作

    }

 

    static User getUserFromDB( int id) {

       省略代码,作用就是真正去查数据

    }

}

分析:重点来看getUser 方法:当我们查询一个数据时,会首先在cache 中查找,如果是第一次查询某数据,cache 中没有存这个数据,会去查数据库。但是如果已经查过数据,便会在cache 中查找到此数据,然后直接返回。可以从控制台中看到:hibernate 只与数据库交互一次。 

为什么要提出缓存的概念 :在前面已经多次说过与数据库建立连接是非常耗资源,而且相当耗时。为了保证高效的查询性能,才提出了缓存的概念。缓存的原理 :当第一次查询时会从数据库中查,当查出数据后会把数据保存在内存中,以后查询时直接从内存中查。当然,实际的缓存要远比此模拟程序复杂,但整个缓存机制是大同小异得,只是它要考虑到更多的细节。 下面来谈谈缓存机制要解决的三个主要问题:

(1) 向缓存中放数据 :一般是发生在查询数据库时,因为每当我们不能从缓存中得到所需数据,便会去数据库中查找,查找完成后我们自然要把它更新缓存中。

(2) 从缓存中取数据 :涉及到一个key 的设置问题,比如我们在模拟程序中,key 的取值来自“id + 类的类型信息”,这样就能保证key 值的唯一性,因为如果仅以id 作为key ,那么其它的类会有相同的id 时,在缓存中就不能区分。

(3) 清掉缓存中失效的数据 :当有其它的操作更新此数据时,原数据将不再正确,这时我们可以选择更新的方式来重新把新的数据更新到缓存中,也可以直接移除原数据,即调用 remove(key)

2.Hibernate 中的一级Session 缓存:

package com.asm.hibernate.test.cacheTest;

public class HibernateCacheTest {

    public static void main(String[] args) {

       addUser ();

       getUser (1);

    }

 

    static User getUser( int id) {

       Session s = null ;

       User user = null ;

       try {

           s = HibernateUtil.getSession ();

           user = (User) s.get(User. class , id);

           System. out .println( "userName:" + user.getName());

 

           // session 缓存,当 session 未关闭时,再查询直接从缓存中获得数据。

           user = (User) s.get(User. class , id);

           System. out .println( "userName:" + user.getName());

 

           // 如果我们清掉缓存,再查询时将会重新连库。

           s.evict(user); // 清掉指定的数据

           // s.clear();// 清掉当前 session 缓存中的所有内容

           user = (User) s.get(User. class , id);

           System. out .println( "userName:" + user.getName());

       } finally {

           if (s != null )

              s.close();

       }

 

       // 当上面的 session 关闭后,如果想再获取前面查询的数据,必须重新查库。

       try {

           s = HibernateUtil.getSession ();

           user = (User) s.get(User. class , id);

           System. out .println( "userName:" + user.getName());

       } finally {

           if (s != null )

              s.close();

       }

       return user;

    }

 

    static void addUser() {

       User user = new User();

       user.setName( "genName" );

       HibernateUtil.add (user);

    }

}

分析 :经过上面的测试和相关说明我们可以得知如下结论:

(1)session 的缓存只在session 未关闭前有效,关闭后再查相同的数据会重新连库

(2) 我们可以手工清除session 中的缓存:evictclear

(3) 如果我们清掉session 中的缓存,或是第一次查询这个数据,都会引起连库

(4)save update,savaOrUpdate,load,get,list,iterate,lock 等方法都会将对象放在一级缓存中, 具体可以在上例的基础上进行测试。

(5)session 一级缓存不能控制缓存数量,所以在大批量操作数据时可能造成内存溢出,这时我们可以用evictclear 来清除缓存中的内容

(6)session web 开发应用中,一般只在一个用户请求时进行缓存,随后将会关闭,这个session 的存活时间很短,所以它的作用不大,因此提出了二级缓存在概念。

3. 二级缓存:

二级缓存通常是第三方来实现,而我们使用时只需要对它进行配置即可。下面演示使用二级缓存的具体步骤。

>> 步骤一 ,在主配置文件中指明支持使用二级缓存:

< property name = "hibernate.cache.use_second_level_cache" > true </ property >

我们也可以不配置此属性,因为默认就是打开二级缓存。

>> 步骤二 、配置第三方缓存机制:

< property name = "hibernate.cache.provider_class" >

           org.hibernate.cache.OSCacheProvider

</ property >     由于我们这里选择了 OSCacheProvider (它貌似也是 hibernate 官方开发得缓存机制) 来提供缓存, 所以还需要把它的缓存配置文件放在src 目录下以使配置能被读到,这里即是把hibernate 解压下的etc 目录中的oscache.properties 文件复制到src 目录下。

>> 步骤三 、两种方式指定要缓存的实体类,一种是在主配置文件中配置( 注意class 是完整的类名) < class-cache class = "com.asm.hibernate.domain.User" usage = "read-only" />

另一种是在实体配置文件(映射文件)配置:比如在User.hbm.xml class 元素下配置如下内容: < cache usage = "read-only" />  关于usage 属性值的说明:

read-only : 如果你的应用程序只需读取一个持久化类的实例,而无需对其修改,那么就可以对其进行 只读 缓存。这是最简单,也是实用性最好的方法。

read-write : 如果应用程序需要更新数据,那么使用“ / 写缓存” 比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level ),那么就决不能使用这种缓存策略。

nonstrict-read-write : 如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离, 那么比较适合使用 非严格读/ 写缓存 策略。
transactional : Hibernate 的事务缓存策略提供了全事务的缓存支持,例如对JBoss TreeCache 的支持。这样的缓存只能用于JTA 环境中,你必须指定为其hibernate.transaction.manager_lookup_class 属性。

>> 步骤四 、测试二级缓存:现在仍用前面的类来测试,尽管第一个session 关闭了,但是我们在第二个session 查询时,仍不会连库,这也就是二级缓存的作用,通常情况下,hibernate 查询时会首先在一级缓存中查询数据,再到二级缓存中查询,如果仍查不到才会连库。 这时请注意,尽管我们在一级缓存中清掉了数据,但是在二级缓存中还存有数据,所以在清掉数据后执行的查询操作也不会引起连库,这就是为什么我们最终只看到一条查询语句的原因。强调 ,前面说用evictclear 只是清掉一级缓存 中的内容。

>> 步骤五 、感知二级缓存:经过上面的测试我们不能明确感知到二级缓存的作用效果,下面我们配置“统计信息”属性来进行二级缓存信息的获取。首先我们在主配置文件中配置以下属性: < property name = "hibernate.generate_statistics" > true </ property > 来打开统计信息,由于统计信息会耗资源,所以一般不打开。然后在测试类的main 方法中增加如下代码:      

       Statistics st = HibernateUtil.getSessionFactory ().getStatistics();

       System. out .println(st);

       System. out .println( "put:" + st.getSecondLevelCachePutCount());

       System. out .println( "hit:" + st.getSecondLevelCacheHitCount());

       System. out .println( "miss:" + st.getSecondLevelCacheMissCount());

执行后结果为:

put:1

hit:2

miss:1     在进行代码结果分析前先来说两个概念:命中,miss 命中 是指在二级缓存中查到数据,没有找到就称为miss .  命中率 :在查询时有多少次是从缓存中得到。 下面我们看上面的执行结果put1, 说明hibernate 放了一次数据到缓存中,这发生在第一次查询时,当不能在二级缓存中找到(这也是为什么会有一次miss 的原因)时,会去连库并把数据放到缓存中去,使put 变为1. 随后进行的三次查找中:第一次仍是从一级缓存中查找到,后两次查找均在二级缓存中查到,所以命中hit=2

4. 二级缓存中的细节问题:

(1) 体会save 自动填充缓存,save 填充缓存不支持idnative 方式生成,所以我们先修改User 的实体配置文件让id 生成方式为:

< id name = "id" >

           < generator class = "hilo" />

</ id > 后,这样修改后再来测试执行结果会发现执行结果为:

put:1
hit:2
miss:1    在进行代码结果分析前先来说两个概念:命中,miss。命中是指在二级缓存中查到数据,没有找到就称为miss.  命中率:在查询时有多少次是从缓存中得到。 下面我们看上面的执行结果put=1,说明hibernate放了一次数据到缓存中,这发生在第一次查询时,当不能在二级缓存中找到(这也是为什么会有一次miss的原因)时,会去连库并把数据放到缓存中去,使put变为1.随后进行的三次查找中:第一次仍是从一级缓存中查找到,后两次查找均在二级缓存中查到,所以命中hit=2。
4.二级缓存中的细节问题:
(1)体会save自动填充缓存,save填充缓存不支持id的native方式生成,所以我们先修改User的实体配置文件让id生成方式为:
<id name="id">
            <generator class="hilo"/>
</id>后,这样修改后再来测试执行结果会发现执行结果为:
put:1
hit:3
miss:0  分析:当我们保存User对象到数据库时也会自动把此数据填充到缓存中,所以第一次put实质是发生在保存数据时。这样也就不难解释为什么hit=3,miss=0了。
(2)除了save外,update、saveOrUpdate、list、iterator、get、load(查询时从二级缓存中取数据的三个方法)、Query、Criteria都会填充二级缓存,且它们支持主键的nativa生成方式。
(3)让Query支持二级缓存:首先是主配置中配置如下属性:
<property name="#hibernate.cache.use_query_cache">true</property>因为Query命中率较低,所以默认此属性是关闭的。随后在Query方式查询时设置q.setCacheable(true);这两步执行后便完成了让Query支持二级缓存。
(4)怎样清除二级缓存:HibernateUtil.getSessionFactory().evict(User.class);这样将清除二级缓存中所有的User类相关的数据。
5.分步式缓存:
首先我们用图来模拟分步式缓存:
 


 
说明:在大型的web系统中,通常都会采用多个服务器来进行web服务,比如在上面的实例中,我们在服务器一存有“数据data”,在服务器二中也存有这个数据,但当我们在服务器N中更改这个数据时,如果我们继续访问在服务器一或二的数据,将不能得到正确的数据,这时采取的方式就是只要有服务器改变这个数据就在这些服务器组成的内网中广播这个信息来更新每个改变的数据。虽然服务器在内网中通讯,但是这种方式也是非常耗资源的,后来提出了“中央缓存”来解决此问题,如下图
 


 
原理:当我们去某个服务器查询数据时,这个服务器会去中央缓存查询,同样如果下面的某个服务器修改数据时,中央缓存也会及时把数据更新到库并重新保存新数据。但是如果数据交互快的话,我们仍不能保证数据这些服务器访问中央缓存时是及时数据。比如在服务器一访问中央缓存修改数据时,其它的几个服务器也能访问修改,这样就不能保证及时获取正确信息。所以使用缓存的条件有如下几点:读取大于写入;数据量不能超过内存容量;对数据要有独立的控制;允许无效的数据存在。
 

 

  • 大小: 14.2 KB
  • 大小: 31.1 KB
分享到:
评论

相关推荐

    Hibernate入门到精通

    "Hibernate入门到精通" Hibernate 是一个基于Java的ORM(Object-Relational Mapping,对象关系映射)框架,它提供了一种简洁高效的方式来访问和操作关系数据库。下面是 Hibernate 的主要知识点: Hibernate 简介 ...

    Hibernate入门jar包

    本压缩包提供的是Hibernate入门所需的jar包,包括了Hibernate的核心库以及与之配合使用的相关组件。让我们深入探讨一下这些jar包以及它们在Hibernate中的作用。 1. Hibernate核心库: - `hibernate-core.jar`:这...

    Hibernate入门案例源码

    【Hibernate入门案例源码】是针对初学者设计的一份教程,旨在帮助理解并掌握Java持久化框架Hibernate的基础应用。Hibernate是一个强大的ORM(对象关系映射)框架,它简化了数据库与Java对象之间的交互,使开发者可以...

    初学hibernate,hibernate入门

    **初学Hibernate,Hibernate入门** Hibernate是一个开源的对象关系映射(ORM)框架,它为Java开发者提供了方便的数据持久化服务。在Java应用中,通过Hibernate,开发者可以将数据库操作抽象成对象模型,使得代码...

    hibernate入门小例子

    【hibernate入门小例子】是一个适合初学者的教程,主要涵盖了如何在JavaWeb项目中使用Hibernate框架与MySQL数据库进行集成。在这个例子中,我们将会深入理解Hibernate的核心概念,包括实体映射、对象关系映射(ORM)...

    Hibernate入门到精通.pdf

    《Hibernate入门到精通》这本书是针对Java开发人员深入学习Hibernate框架的一份宝贵资源。Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序与数据库之间的交互。通过使用Hibernate,...

    Hibernate入门

    ### Hibernate入门知识点详解 #### Hibernate概述与ORM思想 - **定义**:Hibernate是一个开源的、轻量级的对象关系映射(Object-Relational Mapping,简称ORM)框架,它主要应用于JavaEE架构中的DAO(Data Access ...

    hibernate入门--第一个实例

    【hibernate入门--第一个实例】 Hibernate 是一个强大的对象关系映射(ORM)框架,它为Java开发者提供了方便的数据持久化服务。通过使用Hibernate,我们可以将数据库操作转换为对Java对象的操作,从而简化了数据库...

    hibernate入门

    **hibernate入门** Hibernate 是一个强大的Java持久化框架,它简化了数据库操作,使得开发者无需直接编写SQL语句即可实现对象与关系数据库之间的映射。这个文档将带你步入Hibernate的世界,了解其基本概念和核心...

    hibernate教程,hibernate入门

    **Hibernate 教程:带你入门持久化框架** Hibernate 是一个流行的开源对象关系映射(ORM)框架,它为 Java 应用程序提供了便捷的数据持久化服务。本教程将引导你逐步了解 Hibernate 的基本概念、安装配置以及核心...

    hibernate入门实例操作步骤

    **hibernate入门实例操作步骤** Hibernate是一款强大的Java对象关系映射(ORM)框架,它极大地简化了数据库操作,使得开发者可以使用Java对象的方式处理数据库事务。本篇将详细介绍Hibernate入门实例的操作步骤,...

    hibernate入门教程

    Hibernate的入门学习主要包括理解这些基本概念和操作,后续深入学习则会涉及到复杂映射、事务处理、性能优化和缓存管理等高级话题。随着不断实践和学习,开发者可以充分利用Hibernate框架提供的各种特性,编写更加...

    hibernate入门简单实例

    以下是关于Hibernate入门的一些关键知识点: 1. **对象关系映射(ORM)**:ORM是将数据库中的表映射为Java类的过程,通过这种方式,我们可以使用面向对象的编程方式来操作数据,而无需直接编写SQL语句。 2. **...

    hibernate系列(一)hibernate入门

    **hibernate系列(一)hibernate入门** 在Java世界中,ORM(Object-Relational Mapping,对象关系映射)框架是连接数据库与应用程序的重要桥梁,它将数据库中的数据与程序中的对象进行关联,使得开发者可以使用面向...

    java基础入门之Hibernate 入门

    **Java基础入门之Hibernate入门** Hibernate是一个开源的对象关系映射(ORM)框架,它为Java开发者提供了一种在关系数据库中存储和管理对象的便捷方式。在这个“Java基础入门之Hibernate入门”中,我们将深入理解...

    02_传智播客hibernate教程_hibernate入门案例的细节分析

    【标题】:“02_传智播客hibernate教程_hibernate入门案例的细节分析” 在本教程中,我们将深入探讨Hibernate,一个流行的Java对象关系映射(ORM)框架,它简化了数据库操作,使开发者可以更加专注于业务逻辑而不是...

    hibernate入门小程序

    **hibernate入门小程序** Hibernate 是一款开源的对象关系映射(ORM)框架,它为Java开发者提供了方便的数据持久化服务,使得开发人员可以使用面向对象的方式来操作数据库,而无需过多地关注SQL语句的编写。在...

    hibernate官方入门教程 (转载)

    总结,这份“hibernate官方入门教程”可能会教授如何配置Hibernate环境,创建实体类,建立表映射,使用Session和Transaction进行数据操作,以及探索更高级的主题如查询语言、缓存和事务管理。同时,"Lowerthan60's ...

    Hibernate入门.rar

    【Hibernate入门】是一个针对初学者精心整理的教程资源包,旨在帮助新手快速理解并掌握Java持久化框架Hibernate的核心概念和使用方法。这个压缩包包含了所有你需要开始Hibernate学习的基础材料。 Hibernate是一个...

Global site tag (gtag.js) - Google Analytics