精华内容
下载资源
问答
  • 什么需要缓存机制?为提高数据库检索效率而设计缓存机制,针对相同的sql查询,在一级或二级缓存作用范围,只需从缓存中拿取数据即可,而无需从...一级缓存:在sqlSession范围有效,在缓存作用范围,同一sql

    为什么需要缓存机制?为提高数据库检索效率而设计缓存机制,针对相同的sql查询,在一级或二级缓存作用范围内,只需从缓存中拿取数据即可,而无需从数据库中检索数据。缓存是运行内存中的一段内存,而数据库位于硬盘上,从I/O读取数据的速度上来看,从内存读取数据远快于从硬盘上读取,加之从数据库中检索数据的花销,可反衬出缓存机制的强大。

    一级缓存:在sqlSession范围内有效,在缓存作用范围内,同一sql查询,只发出一条sql从数据库中检索数据,并保存于缓存中,每次从缓存中取数据即可。Mybatis默认开启一级缓存。

    package com.dw.dao.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    
    import com.dw.dao.SchoolDao;
    import com.dw.domain.School;
    
    public class testCache {
    	private SqlSession session;
    	private InputStream in;
    	private SchoolDao schoolDao;
    	
      @Test
      public void testOneCahe() {
    	  init();
    	  School school = schoolDao.selectSchool(1);
    	  System.out.println(school);
    	  
    	  school = schoolDao.selectSchool(1);   //两次查询,只发送一条sql语句从数据检索数据
    	  System.out.println(school);
    	  destory();
      }
      
      public void init() {
    	  try {
    		in = Resources.getResourceAsStream("config.xml");
    		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
    		session = sessionFactory.openSession();
    		schoolDao = session.getMapper(SchoolDao.class);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
      }
      
      public void destory() {
    	  if(in != null) {
    		  try {
    			in.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	  }
    	  if(session != null) {
    		  session.close();
    	  }
      }
    }
    
      @Test
      public void testOneCahe() {
    	  init();
    	  School school = schoolDao.selectSchool(1);
    	  System.out.println(school);
    	  
    	  session.close();
    	  init();
    	  school = schoolDao.selectSchool(1);   //不同sqlSession范围,发送两条sql语句从数据检索数据
    	  System.out.println(school);
    	  destory();
      }

      @Test
      public void testOneCahe() {
    	  init();
    	  School school = schoolDao.selectSchool(1);
    	  System.out.println(school);
    	  
    	  school = schoolDao.selectSchoolById(1);   //同一sqlSession范围,不同sql查询,发送两条sql语句从数据检索数据
    	  System.out.println(school);
    	  destory();
      }
      @Test
      public void testOneCahe() {
    	  init();
    	  School school = schoolDao.selectSchool(1);
    	  System.out.println(school);
    	  
    	  School sch = new School();
    	  school.setName("北京大学");
    	  schoolDao.insertSchool(sch);
    	  
    	  school = schoolDao.selectSchool(1);   //同一sqlSession范围,同一sql查询,但中间执行了insert操作,发送两条相同sql语句从数据库检索数据
    	  System.out.println(school);
    	  destory();
      }

    四种情况致使一级缓存失效:
    1)同一sql查询,不同sqlSession范围

    2)同一sqlSession,不同sql查询

    3)同一sql查询,其中间执行了增、删、改等操作

    4)执行了commit或清除缓存等操作

    ---------------------------------------------------------------------------------------------------

    二级缓存:(情况一:Mybatis内置)

    二级缓存是作用在namespace下,基于mapper.xml配置的缓存,其作用范围是sessionFactory,并且,只有sqlSession关闭或者提交后,二级缓存才起作用。

    1)在全局配置文件config.xml中开启二级缓存,默认开启:<setting name="cacheEnabled" value="true"/>

    2)将对应的pojo类序列化serializable。换言之,就是序列化与反序列化的过程

    3)在mapper.xml文件中配置:<cache eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>其中flushInterval是设置刷新缓存时间间隔,一般设置flashCache="true",这样在增加、删除、修改数据会默认刷新数据库,避免了读取脏数据。

     @Test
      public void testTwoCache() {
    	  try {
    		  in = Resources.getResourceAsStream("config.xml");
    		  SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
    		  SqlSession session1 = sessionFactory.openSession();
    		  schoolDao = session1.getMapper(SchoolDao.class);
    		  School school = schoolDao.selectSchool(1);
    		  System.out.println(school);
              session1.close();  //不同session,一定要关闭或者提交
          
              SqlSession session2 = sessionFactory.openSession();
              schoolDao = session2.getMapper(SchoolDao.class);
    		  school = schoolDao.selectSchool(1);
    		  /**此用例会发出一条sql */
    		  System.out.println(school);
    	
    	} catch (Exception e) {
    	}
      }

    作用范围:sessionFactory:

      @Test
      public void testTwoCache() {
    	  try {
    		  in = Resources.getResourceAsStream("config.xml");
    		  SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
    		  SqlSession session1 = sessionFactory.openSession();
    		  schoolDao = session1.getMapper(SchoolDao.class);
    		  School school = schoolDao.selectSchool(1);
    		  System.out.println(school);
              session1.close();  //不同session,一定要关闭或者提交
          
              in.close();
              in = Resources.getResourceAsStream("config.xml");
              /**二级缓存必须在同一个sessionFactory下才有效*/
              sessionFactory = new SqlSessionFactoryBuilder().build(in);
              SqlSession session2 = sessionFactory.openSession();
              schoolDao = session2.getMapper(SchoolDao.class);
    		  school = schoolDao.selectSchool(1);
    		  /**此用例会发出两条相同sql ,因为在不同的sessionFacory下*/
    		  System.out.println(school);
    	
    	} catch (Exception e) {
    	}
      }

    ---------------------------------------------------------------------------------------------------

    二级缓存(情况二:使用第三方缓存框架cache)  pojo无需序列化

    1)下载ehcache相关jar包(http://github.com/mybatis)下载ehcache-cache

    2)在mapper.xml中配置:

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

    3)在类路径下配置ehcache.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache>
        <diskStore path="d:/ehcache/"></diskStore>
        
        <!-- 默认缓存配置 -->
        <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
        />
        
        <!-- User缓存配置 -->
        <cache 
            name="User" 
            maxElementsInMemory="10000" 
            eternal="false"
            timeToIdleSeconds="300" 
            timeToLiveSeconds="600" 
            overflowToDisk="true" 
        />
    
    </ehcache>


      @Test
      public void testTwoCache() {
    	  try {
    		  in = Resources.getResourceAsStream("config.xml");
    		  SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
    		  SqlSession session1 = sessionFactory.openSession();
    		  schoolDao = session1.getMapper(SchoolDao.class);
    		  School school = schoolDao.selectSchool(1);
    		  System.out.println(school);
    		  session1.close();  //不同session,一定要关闭或者提交
              SqlSession session2 = sessionFactory.openSession();
              schoolDao = session2.getMapper(SchoolDao.class);
    		  school = schoolDao.selectSchool(1);
    		  /**此用例会发出一条sql */
    		  System.out.println(school);
    	
    	} catch (Exception e) {
    	}
      }
    如果要在不同的namespace下共享cache的配置,在mapper.xml中引入<cache-ref namespace="com.dw.dao.SchoolDao"/>即可。




    展开全文
  • 缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的

    缓存:缓存是什么,解决什么问题? 
    位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为缓存Cache。缓存目的:让数据更接近于应用程序,协调速度不匹配,使访问速度更快。 

    缓存的范围分为3类: 
    1.事务范围(单Session即一级缓存) 
       事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围. 
    2.应用范围(单SessionFactory即二级缓存) 
       应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围. 
    3.集群范围(多SessionFactory) 
       在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致,缓存中的数据通常采用对象的松散数据形式.

    二级缓存如何工作的 
    Hibernate的二级缓存同一级缓存一样,也是针对对象ID来进行缓存。所以说,二级缓存的作用范围是针对根据ID获得对象的查询。 
    ● 在执行各种条件查询时,如果所获得的结果集为实体对象的集合,那么就会把所有的数据对象根据ID放入到二级缓存中。 
    ● 当Hibernate根据ID访问数据对象的时候,首先会从Session一级缓存中查找,如果查不到并且配置了二级缓存,那么会从二级缓存中查找,如果还查不到,就会查询数据库,把结果按照ID放入到缓存中。 
    ● 删除、更新、增加数据的时候,同时更新缓存。 

    与Hibernate一级缓存Session范围相对的是SessionFactory范围的二级缓存,SessionFactory也提供了相应的缓存机制。SessionFactory缓存可以依据功能和目的的不同而划分为内置缓存和外置缓存。 

    SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的副本,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来的。SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。 

    SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的副本,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的二级缓存。 

    Hibernate的二级缓存的实现原理与一级缓存是一样的,也是通过以ID为key的Map来实现对对象的缓存。 

    二级缓存是缓存实体对象的,由于Hibernate的二级缓存是作用在SessionFactory范围内的,因而它比一级缓存的范围更广,可以被所有的Session对象所共享。 

    在通常情况下会将具有以下特征的数据放入到二级缓存中: 
    ● 很少被修改的数据。 
    ● 不是很重要的数据,允许出现偶尔并发的数据。 
    ● 不会被并发访问的数据。 
    ● 常量数据。 
    ● 不会被第三方修改的数据 

    而对于具有以下特征的数据则不适合放在二级缓存中: 
    ● 经常被修改的数据。 
    ● 财务数据,绝对不允许出现并发。 
    ● 与其他应用共享的数据。 

    在这里特别要注意的是对放入缓存中的数据不能有第三方的应用对数据进行更改(其中也包括在自己程序中使用其他方式进行数据的修改,例如,JDBC),因为那样Hibernate将不会知道数据已经被修改,也就无法保证缓存中的数据与数据库中数据的一致性。 

    常见的缓存组件 
    在默认情况下,Hibernate会使用EHCache作为二级缓存组件。但是,可以通过设置hibernate.cache.provider_class属性,指定其他的缓存策略,该缓存策略必须实现org.hibernate.cache.CacheProvider接口。 
    通过实现org.hibernate.cache.CacheProvider接口可以提供对不同二级缓存组件的支持,此接口充当缓存插件与Hibernate之间的适配器。 

    组件 Provider类 类型 集群 查询缓存
    Hashtable org.hibernate.cache.HashtableCacheProvider 内存 不支持 支持
    EHCache org.hibernate.cache.EhCacheProvider 内存,硬盘 不支持 支持
    OSCache org.hibernate.cache.OSCacheProvider 内存,硬盘 支持 支持
    SwarmCache org.hibernate.cache.SwarmCacheProvider 集群 支持 不支持
    JBoss TreeCache org.hibernate.cache.TreeCacheProvider 集群 支持 支持


    Hibernate已经不再提供对JCS(Java Caching System)组件的支持了。 
    集群缓存的概念: 
    当一台服务器上的执行了update方法修改了一条数据,那么只有这一台服务器上的二级缓存会同步于数据库,其他服务器上的二级缓存里面这条数据就没意义了。这个时候用OSCache缓存机制,只要有一台服务器上有数据修改了,马上会从配置文件中找到配置好的其他服务器IP地址,进行广播,告诉他们我这条数据修改了,你们也更新同步一下。(是不是有点像手机上微博的推送功能) 

    如何在程序里使用二级缓存: 
    首先在hibernate.cfg.xml开启二级缓存 

    1. <hibernate-configuration>  
    2.    <session-factory>  
    3.   
    4.       ......  
    5.   
    6.       <!-- 开启二级缓存 -->  
    7.       <property name="hibernate.cache.use_second_level_cache">true</property>  
    8.       <!-- 启动"查询缓存"如果想缓存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集,必须配置此项-->  
    9.       <property name="hibernate.cache.use_query_cache">true</property>  
    10.       <!-- 设置二级缓存插件EHCache的Provider类-->  
    11.       <!-- <property name="hibernate.cache.provider_class">  
    12.          org.hibernate.cache.EhCacheProvider  
    13.       </property> -->  
    14.       <!-- 二级缓存区域名的前缀 -->  
    15.       <!--<property name="hibernate.cache.region_prefix">test</property>-->  
    16.       <!-- 高速缓存提供程序 -->  
    17.       <property name="hibernate.cache.region.factory_class">  
    18.          net.sf.ehcache.hibernate.EhCacheRegionFactory  
    19.       </property>  
    20.       <!-- Hibernate4以后都封装到org.hibernate.cache.ehcache.EhCacheRegionFactory -->  
    21.       <!-- 指定缓存配置文件位置 -->  
    22.       <!-- <property name="hibernate.cache.provider_configuration_file_resource_path">  
    23.          ehcache.xml  
    24.       </property> -->  
    25.       <!-- 强制Hibernate以更人性化的格式将数据存入二级缓存 -->  
    26.       <property name="hibernate.cache.use_structured_entries">true</property>  
    27.   
    28.       <!-- Hibernate将收集有助于性能调节的统计数据 -->  
    29.       <property name="hibernate.generate_statistics">true</property>  
    30.   
    31.       ......  
    32.   
    33.    </session-factory>  
    34. </hibernate-configuration>  


    然后是ehcache配置(ehcache.xml) 
    cache参数详解: 
    ● name:指定区域名 
    ● maxElementsInMemory :缓存在内存中的最大数目 
    ● maxElementsOnDisk:缓存在磁盘上的最大数目 
    ● eternal :设置是否永远不过期 
    ● overflowToDisk : 硬盘溢出数目 
    ● timeToIdleSeconds :对象处于空闲状态的最多秒数后销毁 
    ● timeToLiveSeconds :对象处于缓存状态的最多秒数后销毁 
    ● memoryStoreEvictionPolicy:缓存算法,有LRU(默认)、LFU、LFU 

    关于缓存算法,常见有三种: 
    ● LRU:(Least Rencently Used)新来的对象替换掉使用时间算最近很少使用的对象 
    ● LFU:(Least Frequently Used)替换掉按命中率高低算比较低的对象 
    ● LFU:(First In First Out)把最早进入二级缓存的对象替换掉 


    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <ehcache>  
    3.   <!--如果缓存中的对象存储超过指定的缓存数量的对象存储的磁盘地址-->  
    4.   <diskStore path="D:/ehcache"/>  
    5.   
    6.   <!-- 默认cache:如果没有对应的特定区域的缓存,就使用默认缓存 -->  
    7.   <defaultCache maxElementsInMemory="10000"  
    8.                 eternal="false"  
    9.                 timeToIdleSeconds="300"   
    10.                 timeToLiveSeconds="600"  
    11.                 overflowToDisk="false"/>  
    12.   <!-- 指定区域cache:通过name指定,name对应到Hibernate中的区域名即可-->  
    13.   <cache name="cn.javass.h3test.model.UserModel"  
    14.                 eternal="false"  
    15.                 maxElementsInMemory="100"  
    16.                 timeToIdleSeconds="1200"  
    17.                 timeToLiveSeconds="1200"  
    18.                 overflowToDisk="false">  
    19.   </cache>  
    20.   
    21. </ehcache>  


    在每个实体的hbm文件中配置cache元素,usage可以是read-only或者是read-write等4种。 

    1. <?xml version="1.0" encoding='UTF-8'?>  
    2. <!DOCTYPE hibernate-mapping PUBLIC  
    3.                             "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    4.                             "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd>  
    5. <hibernate-mapping>      
    6.    <class>  
    7.        <!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->  
    8.        <class name="cn.java.test.model.User" table="TBL_USER">  
    9.               <cache usage="read-write"/>  
    10.        ......    
    11.    </class>  
    12. </hibernate-mapping>  


    也可以用Hibernate注解配置缓存实体类 

    1. @Entity    
    2. @Table    
    3. @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)  
    4. public class User implements Serializable {    
    5.     private static final long serialVersionUID = -5121812640999313420L;  
    6.     private Integer id;  
    7.     private String name;  
    8.   
    9.     ......  
    10. }  


    Query或Criteria接口查询时设置其setCacheable(true): 
    默认的如果不在程序中显示的执行查询缓存声明操作,Hibernate是不会对查询的list进行缓存的。 

    1. Session s1= HibernateSessionFactory.getCurrentSession();  
    2. s1.beginTransaction();  
    3. System.out.println("第一次查询User");  
    4. Query q = s1.createQuery("from User");  
    5. q.setCacheable(true);  
    6. q.list();  
    7. System.out.println("放进二级缓存");  
    8. s1.getTransaction().commit();  
    9.   
    10. Session s2= HibernateSessionFactory.getCurrentSession();  
    11. s2.beginTransaction();  
    12. System.out.println("第二次查询User,将不会发出sql");  
    13. Query q = s2.createQuery("from User");  
    14. q.setCacheable(true);  
    15. q.list();  
    16. s2.getTransaction().commit();  
    17.   
    18. //如果配置文件打开了generate_statistics性能调解,可以得到二级缓存命中次数等数据  
    19. Statistics s = HibernateSessionFactoryUtil.getSessionFactory().getStatistics();  
    20. System.out.println(s);  
    21. System.out.println("put:"+s.getSecondLevelCachePutCount());  
    22. System.out.println("hit:"+s.getSecondLevelCacheHitCount());  
    23. System.out.println("miss:"+s.getSecondLevelCacheMissCount());  


    如果开启了二级缓存,由于session是共享二级缓存的,只要缓存里面有要查询的对象,就不会向数据库发出sql,如果在二级缓存里没有找到需要的数据就会发出sql语句去数据库拿。 

    一级缓存的管理: 
    ● evit(Object obj)将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象. 
    ● clear()将一级缓存中的所有持久化对象清除,释放其占用的内存资源 
    ● contains(Object obj)判断指定的对象是否存在于一级缓存中. 
    ● flush()刷新一级缓存区的内容,使之与数据库数据保持同步. 

    二级缓存的管理: 
    ● evict(Class arg0, Serializable arg1)将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源. 

    1. sessionFactory.evict(Customer.class, new Integer(1));  


    evict(Class arg0)将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源 

    1. sessionFactory.evict(Customer.class);  


    evictCollection(String arg0)将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源. 

    1. sessionFactory.evictCollection("Customer.orders");  



    设置一级缓存和二级缓存的交互权限 

    1. session = HibernateUtils.getSession();  
    2. session.beginTransaction();  
    3.               
    4. //仅向二级缓存读数据,而不向二级缓存写数据,这里load的数据就不会放入二级缓存,下次再查还是会去数据库拿  
    5. session.setCacheMode(CacheMode.GET);  
    6. //只向二级缓存写数据,而不从二级缓存读数据  
    7. //session.setCacheMode(CacheMode.PUT);  
    8. //不与二级缓存交互  
    9. //session.setCacheMode(CacheMode.IGNORE);  
    10. //可以与二级缓存交互  
    11. //session.setCacheMode(CacheMode.NORMAL);  
    12.   
    13. Student student = (Student)session.load(Student.class, 1);  
    14.   
    15. session.getTransaction().commit();  


    设置二级缓存策略 
    ● READ_ONLY:实体只读缓存 
       只读缓存不允许更新,将报错Can't write to a readonly object。 
       允许新增,(从2.0以后新增直接添加到二级缓存) 

    1. //确保数据库中有标识符为1的FarmModel    
    2. FarmModel farm = (FarmModel) session.get(FarmModel.class, 1);    
    3. //如果修改将报错,只读缓存不允许修改    
    4. //farm.setName("aaa");  


    ● NONSTRICT_READ_WRITE:实体非严格读/写缓存 
       允许更新,更新后缓存失效,需再查询一次。 
       允许新增,新增记录自动加到二级缓存中。 
       整个过程不加锁。 
    ● READ_WRITE:实体读/写缓存 
       允许更新,更新后自动同步到缓存。 
       允许新增,新增记录后自动同步到缓存。 
       保证read committed隔离级别及可重复读隔离级别(通过时间戳实现) 
       整个过程加锁,如果当前事务的时间戳早于二级缓存中的条目的时间戳,说明该条目已经被别的 
       事务修改了,此时重新查询一次数据库,否则才使用缓存数据,因此保证可重复读隔离级别。 
       读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁 
    ● TRANSACTIONAL:实体事务缓存 
       缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境 
    ● Collection集合缓存 

    1. <hibernate-mapping>  
    2.     <class name="cn.java.test.model.UserModel" table="TBL_USER">  
    3.         <cache usage="read-write" />  
    4.         <set name="farms" cascade="all" inverse="true" lazy="false">  
    5.             <cache usage="read-write"/>  
    6.             <key column="fk_user_id"/>  
    7.             <one-to-many class="cn.java.test.model.FarmModel"/>  
    8.         </set>  
    9.     </class>  
    10. </hibernate-mapping>  



    和实体并发策略有相同含义; 
    但集合缓存只缓存集合元素的标识符,在二级缓存中只存放相应实体的标识符,然后再通过标识符去二级缓存查找相应的实体最后组合为集合返回 
    Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。 
    这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新 

    高速缓存区域 
    Hibernate在不同的高速缓存区域保存不同的类(实体)/集合,如果不配置区域默认都保存到“默认缓存”(defaultCache)中。 
    ●每一个区域可以设置过期策略、缓存条目大小等等。 
    ●对于类缓存,默认区域名是全限定类名,如cn.javass.h3test.model.UserModel。 
    ●对于集合而言,默认区域名是全限定类名+属性名,如cn.javass.….UserModel.farms。 
    ●可通过hibernate.cache.region_prefix指定特定SessionFactory的区域前缀,如前缀是h3test,则如类缓存的区域名就是h3test.cn.javass.h3test.model.UserModel。如果应用程序使用多个SessionFactory这可能是必须的。 
    可通过<cache usage="read-write" region="区域名"/>自定义区域名,不过默认其实就可以了。 

    一些对二级缓存的理解 
    当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢? 
    hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。 
    当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。 
    如果找到的时间戳晚于高速缓存查询结果的时间戳,那么缓存结果将被丢弃,重新执行一次查询。 
    可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。 

    使用二级缓存的前置条件 
    对于那些查询非常多但插入、删除、更新非常少的应用程序来说,查询缓存可提升性能。但写入多查询少的没有用,总失效。 
    hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。 
    你操作数据库必需直接通过hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。 
    这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化。 
    当然可以用SessionFactory提供的移除缓存的方法(上面的二级缓存的管理里面有介绍) 

    总结 
    不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。 

    如果受不了Hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧! 
    在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧!

    展开全文
  • 什么一级缓存

    千次阅读 2008-10-30 14:15:00
    导读:CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器,它的容量比内存小的多但是交换速度却比内存要快得多。...在缓存中的数据是内存中的小部分,但这小部分是短时间CPU即将访问的,当CPU调用大量数据
    导读:
    




    CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器,
    它的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读
    写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。在缓存中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的,
    当CPU调用大量数据时,就可避开内存直接从缓存中调用,从而加快读取速度。由此可见,在CPU中加入缓存是一种高效的解决方案,这样整个内存储器(缓
    存+内存)就变成了既有缓存的高速度,又有内存的大容量的存储系统了。缓存对CPU的性能影响很大,主要是因为CPU的数据交换顺序和CPU与缓存间的带
    宽引起的。

       
    缓存的工作原理是当CPU要读取一个数据时,首先从缓存中查找,如果找到就立即读取并送给CPU处理;如果没有找到,就用相对慢的速度从内存中读取并送给
    CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。


       
    正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右),也就是说CPU下一次要读取的数据90%都在缓存中,只有大约10%
    需要从内存读取。这大大节省了CPU直接读取内存的时间,也使CPU读取数据时基本无需等待。总的来说,CPU读取数据的顺序是先缓存后内存。


        目前缓存基本上都是采用SRAM存储器,SRAM是英文Static
    RAM的缩写,它是一种具有静志存取功能的存储器,不需要刷新电路即能保存它内部存储的数据。不像DRAM内存那样需要刷新电路,每隔一段时间,固定要对
    DRAM刷新充电一次,否则内部的数据即会消失,因此SRAM具有较高的性能,但是SRAM也有它的缺点,即它的集成度较低,相同容量的DRAM内存可以
    设计为较小的体积,但是SRAM却需要很大的体积,这也是目前不能将缓存容量做得太大的重要原因。它的特点归纳如下:优点是节能、速度快、不必配合内存刷
    新电路、可提高整体的工作效率,缺点是集成度低、相同的容量体积较大、而且价格较高,只能少量用于关键性系统以提高效率。


       
    按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下
    一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。当CPU要读取一个数据时,首先从一级缓存中查找,如果没有
    找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。一般来说,每级缓存的命中率大概都在80%左右,也就是说全部数据量的80%都可以在一
    级缓存中找到,只剩下20%的总数据量才需要从二级缓存、三级缓存或内存中读取,由此可见一级缓存是整个CPU缓存架构中最为重要的部分。


        一级缓存(Level 1 Cache)简称L1
    Cache,位于CPU内核的旁边,是与CPU结合最为紧密的CPU缓存,也是历史上最早出现的CPU缓存。由于一级缓存的技术难度和制造成本最高,提高
    容量所带来的技术难度增加和成本增加非常大,所带来的性能提升却不明显,性价比很低,而且现有的一级缓存的命中率已经很高,所以一级缓存是所有缓存中容量
    最小的,比二级缓存要小得多。


        一般来说,一级缓存可以分为一级数据缓存(Data
    Cache,D-Cache)和一级指令缓存(Instruction
    Cache,I-Cache)。二者分别用来存放数据以及对执行这些数据的指令进行即时解码,而且两者可以同时被CPU访问,减少了争用Cache所造成
    的冲突,提高了处理器效能。目前大多数CPU的一级数据缓存和一级指令缓存具有相同的容量,例如AMD的Athlon
    XP就具有64KB的一级数据缓存和64KB的一级指令缓存,其一级缓存就以64KB+64KB来表示,其余的CPU的一级缓存表示方法以此类推。


        Intel的采用NetBurst架构的CPU(最典型的就是Pentium
    4)的一级缓存有点特殊,使用了新增加的一种一级追踪缓存(Execution Trace
    Cache,T-Cache或ETC)来替代一级指令缓存,容量为12KμOps,表示能存储12K条即12000条解码后的微指令。一级追踪缓存
    与一级指令缓存的运行机制是不相同的,一级指令缓存只是对指令作即时的解码而并不会储存这些指令,而一级追踪缓存同样会将一些指令作解码,这些指令称为微
    指令(micro-ops),而这些微指令能储存在一级追踪缓存之内,无需每一次都作出解码的程序,因此一级追踪缓存能有效地增加在高工作频率下对指令的
    解码能力,而μOps就是micro-ops,也就是微型操作的意思。它以很高的速度将μops提供给处理器核心。Intel
    NetBurst微型架构使用执行跟踪缓存,将解码器从执行循环中分离出来。这个跟踪缓存以很高的带宽将uops提供给核心,从本质上适于充分利用软件中
    的指令级并行机制。Intel并没有公布一级追踪缓存的实际容量,只知道一级追踪缓存能储存12000条微指令(micro-ops)。所以,我们不能简
    单地用微指令的数目来比较指令缓存的大小。实际上,单核心的NetBurst架构CPU使用8Kμops的缓存已经基本上够用了,多出的
    4kμops可以大大提高缓存命中率。而如果要使用超线程技术的话,12KμOps就会有些不够用,这就是为什么有时候Intel处理器在使
    用超线程技术时会导致性能下降的重要原因。


       
    例如Northwood核心的一级缓存为8KB+12KμOps,就表示其一级数据缓存为8KB,一级追踪缓存为12KμOps;而
    Prescott核心的一级缓存为16KB+12KμOps,就表示其一级数据缓存为16KB,一级追踪缓存为12KμOps。在这里
    12KμOps绝对不等于12KB,单位都不同,一个是μOps,一个是Byte(字节),而且二者的运行机制完全不同。所以那些把
    Intel的CPU一级缓存简单相加,例如把Northwood核心说成是20KB一级缓存,把Prescott核心说成是28KB一级缓存,并且据此认
    为Intel处理器的一级缓存容量远远低于AMD处理器128KB的一级缓存容量的看法是完全错误的,二者不具有可比性。在架构有一定区别的CPU对比
    中,很多缓存已经难以找到对应的东西,即使类似名称的缓存在设计思路和功能定义上也有区别了,此时不能用简单的算术加法来进行对比;而在架构极为近似的
    CPU对比中,分别对比各种功能缓存大小才有一定的意义。

     



    本文转自

    http://publish.it168.com/cWord/3498.shtml
    展开全文
  • 缓存:缓存是什么,解决什么问题? 位于速度相差较大的两种硬件/软件之间的,用于协调两者...事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互...
    缓存:缓存是什么,解决什么问题? 
    位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为缓存Cache。缓存目的:让数据更接近于应用程序,协调速度不匹配,使访问速度更快。 

    缓存的范围分为3类: 
    1.事务范围(单Session即一级缓存) 
       事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围. 
    2.应用范围(单SessionFactory即二级缓存) 
       应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围. 
    3.集群范围(多SessionFactory) 
       在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致,缓存中的数据通常采用对象的松散数据形式.

    二级缓存如何工作的 
    Hibernate的二级缓存同一级缓存一样,也是针对对象ID来进行缓存。所以说,二级缓存的作用范围是针对根据ID获得对象的查询。 
    ● 在执行各种条件查询时,如果所获得的结果集为实体对象的集合,那么就会把所有的数据对象根据ID放入到二级缓存中。 
    ● 当Hibernate根据ID访问数据对象的时候,首先会从Session一级缓存中查找,如果查不到并且配置了二级缓存,那么会从二级缓存中查找,如果还查不到,就会查询数据库,把结果按照ID放入到缓存中。 
    ● 删除、更新、增加数据的时候,同时更新缓存。 

    与Hibernate一级缓存Session范围相对的是SessionFactory范围的二级缓存,SessionFactory也提供了相应的缓存机制。SessionFactory缓存可以依据功能和目的的不同而划分为内置缓存和外置缓存。 

    SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的副本,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来的。SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。 

    SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的副本,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的二级缓存。 

    Hibernate的二级缓存的实现原理与一级缓存是一样的,也是通过以ID为key的Map来实现对对象的缓存。 

    二级缓存是缓存实体对象的,由于Hibernate的二级缓存是作用在SessionFactory范围内的,因而它比一级缓存的范围更广,可以被所有的Session对象所共享。 

    在通常情况下会将具有以下特征的数据放入到二级缓存中: 
    ● 很少被修改的数据。 
    ● 不是很重要的数据,允许出现偶尔并发的数据。 
    ● 不会被并发访问的数据。 
    ● 常量数据。 
    ● 不会被第三方修改的数据 

    而对于具有以下特征的数据则不适合放在二级缓存中: 
    ● 经常被修改的数据。 
    ● 财务数据,绝对不允许出现并发。 
    ● 与其他应用共享的数据。 

    在这里特别要注意的是对放入缓存中的数据不能有第三方的应用对数据进行更改(其中也包括在自己程序中使用其他方式进行数据的修改,例如,JDBC),因为那样Hibernate将不会知道数据已经被修改,也就无法保证缓存中的数据与数据库中数据的一致性。 

    常见的缓存组件 
    在默认情况下,Hibernate会使用EHCache作为二级缓存组件。但是,可以通过设置hibernate.cache.provider_class属性,指定其他的缓存策略,该缓存策略必须实现org.hibernate.cache.CacheProvider接口。 
    通过实现org.hibernate.cache.CacheProvider接口可以提供对不同二级缓存组件的支持,此接口充当缓存插件与Hibernate之间的适配器。 
    组件 Provider类 类型 集群 查询缓存
    Hashtable org.hibernate.cache.HashtableCacheProvider 内存 不支持 支持
    EHCache org.hibernate.cache.EhCacheProvider 内存,硬盘 不支持 支持
    OSCache org.hibernate.cache.OSCacheProvider 内存,硬盘 支持 支持
    SwarmCache org.hibernate.cache.SwarmCacheProvider 集群 支持 不支持
    JBoss TreeCache org.hibernate.cache.TreeCacheProvider 集群 支持 支持

    Hibernate已经不再提供对JCS(Java Caching System)组件的支持了。 
    集群缓存的概念: 
    当一台服务器上的执行了update方法修改了一条数据,那么只有这一台服务器上的二级缓存会同步于数据库,其他服务器上的二级缓存里面这条数据就没意义了。这个时候用OSCache缓存机制,只要有一台服务器上有数据修改了,马上会从配置文件中找到配置好的其他服务器IP地址,进行广播,告诉他们我这条数据修改了,你们也更新同步一下。(是不是有点像手机上微博的推送功能) 

    如何在程序里使用二级缓存: 
    首先在hibernate.cfg.xml开启二级缓存 
    Xml代码  收藏代码
    1. <hibernate-configuration>  
    2.    <session-factory>  
    3.   
    4.       ......  
    5.   
    6.       <!-- 开启二级缓存 -->  
    7.       <property name="hibernate.cache.use_second_level_cache">true</property>  
    8.       <!-- 启动"查询缓存"如果想缓存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集,必须配置此项-->  
    9.       <property name="hibernate.cache.use_query_cache">true</property>  
    10.       <!-- 设置二级缓存插件EHCache的Provider类-->  
    11.       <!-- <property name="hibernate.cache.provider_class">  
    12.          org.hibernate.cache.EhCacheProvider  
    13.       </property> -->  
    14.       <!-- 二级缓存区域名的前缀 -->  
    15.       <!--<property name="hibernate.cache.region_prefix">test</property>-->  
    16.       <!-- 高速缓存提供程序 -->  
    17.       <property name="hibernate.cache.region.factory_class">  
    18.          net.sf.ehcache.hibernate.EhCacheRegionFactory  
    19.       </property>  
    20.       <!-- Hibernate4以后都封装到org.hibernate.cache.ehcache.EhCacheRegionFactory -->  
    21.       <!-- 指定缓存配置文件位置 -->  
    22.       <!-- <property name="hibernate.cache.provider_configuration_file_resource_path">  
    23.          ehcache.xml  
    24.       </property> -->  
    25.       <!-- 强制Hibernate以更人性化的格式将数据存入二级缓存 -->  
    26.       <property name="hibernate.cache.use_structured_entries">true</property>  
    27.   
    28.       <!-- Hibernate将收集有助于性能调节的统计数据 -->  
    29.       <property name="hibernate.generate_statistics">true</property>  
    30.   
    31.       ......  
    32.   
    33.    </session-factory>  
    34. </hibernate-configuration>  

    然后是ehcache配置(ehcache.xml) 
    cache参数详解: 
    ● name:指定区域名 
    ● maxElementsInMemory :缓存在内存中的最大数目 
    ● maxElementsOnDisk:缓存在磁盘上的最大数目 
    ● eternal :设置是否永远不过期 
    ● overflowToDisk : 硬盘溢出数目 
    ● timeToIdleSeconds :对象处于空闲状态的最多秒数后销毁 
    ● timeToLiveSeconds :对象处于缓存状态的最多秒数后销毁 
    ● memoryStoreEvictionPolicy:缓存算法,有LRU(默认)、LFU、LFU 

    关于缓存算法,常见有三种: 
    ● LRU:(Least Rencently Used)新来的对象替换掉使用时间算最近很少使用的对象 
    ● LFU:(Least Frequently Used)替换掉按命中率高低算比较低的对象 
    ● LFU:(First In First Out)把最早进入二级缓存的对象替换掉 


    Xml代码  收藏代码
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <ehcache>  
    3.   <!--如果缓存中的对象存储超过指定的缓存数量的对象存储的磁盘地址-->  
    4.   <diskStore path="D:/ehcache"/>  
    5.   
    6.   <!-- 默认cache:如果没有对应的特定区域的缓存,就使用默认缓存 -->  
    7.   <defaultCache maxElementsInMemory="10000"  
    8.                 eternal="false"  
    9.                 timeToIdleSeconds="300"   
    10.                 timeToLiveSeconds="600"  
    11.                 overflowToDisk="false"/>  
    12.   <!-- 指定区域cache:通过name指定,name对应到Hibernate中的区域名即可-->  
    13.   <cache name="cn.javass.h3test.model.UserModel"  
    14.                 eternal="false"  
    15.                 maxElementsInMemory="100"  
    16.                 timeToIdleSeconds="1200"  
    17.                 timeToLiveSeconds="1200"  
    18.                 overflowToDisk="false">  
    19.   </cache>  
    20.   
    21. </ehcache>  

    在每个实体的hbm文件中配置cache元素,usage可以是read-only或者是read-write等4种。 
    Xml代码  收藏代码
    1. <?xml version="1.0" encoding='UTF-8'?>  
    2. <!DOCTYPE hibernate-mapping PUBLIC  
    3.                             "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    4.                             "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd>  
    5. <hibernate-mapping>      
    6.    <class>  
    7.        <!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->  
    8.        <class name="cn.java.test.model.User" table="TBL_USER">  
    9.               <cache usage="read-write"/>  
    10.        ......    
    11.    </class>  
    12. </hibernate-mapping>  

    也可以用Hibernate注解配置缓存实体类 
    Java代码  收藏代码
    1. @Entity    
    2. @Table    
    3. @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)  
    4. public class User implements Serializable {    
    5.     private static final long serialVersionUID = -5121812640999313420L;  
    6.     private Integer id;  
    7.     private String name;  
    8.   
    9.     ......  
    10. }  

    Query或Criteria接口查询时设置其setCacheable(true): 
    默认的如果不在程序中显示的执行查询缓存声明操作,Hibernate是不会对查询的list进行缓存的。
     
    Java代码  收藏代码
    1. Session s1= HibernateSessionFactory.getCurrentSession();  
    2. s1.beginTransaction();  
    3. System.out.println("第一次查询User");  
    4. Query q = s1.createQuery("from User");  
    5. q.setCacheable(true);  
    6. q.list();  
    7. System.out.println("放进二级缓存");  
    8. s1.getTransaction().commit();  
    9.   
    10. Session s2= HibernateSessionFactory.getCurrentSession();  
    11. s2.beginTransaction();  
    12. System.out.println("第二次查询User,将不会发出sql");  
    13. Query q = s2.createQuery("from User");  
    14. q.setCacheable(true);  
    15. q.list();  
    16. s2.getTransaction().commit();  
    17.   
    18. //如果配置文件打开了generate_statistics性能调解,可以得到二级缓存命中次数等数据  
    19. Statistics s = HibernateSessionFactoryUtil.getSessionFactory().getStatistics();  
    20. System.out.println(s);  
    21. System.out.println("put:"+s.getSecondLevelCachePutCount());  
    22. System.out.println("hit:"+s.getSecondLevelCacheHitCount());  
    23. System.out.println("miss:"+s.getSecondLevelCacheMissCount());  

    如果开启了二级缓存,由于session是共享二级缓存的,只要缓存里面有要查询的对象,就不会向数据库发出sql,如果在二级缓存里没有找到需要的数据就会发出sql语句去数据库拿。 

    一级缓存的管理: 
    ● evit(Object obj)将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象. 
    ● clear()将一级缓存中的所有持久化对象清除,释放其占用的内存资源 
    ● contains(Object obj)判断指定的对象是否存在于一级缓存中. 
    ● flush()刷新一级缓存区的内容,使之与数据库数据保持同步. 

    二级缓存的管理: 
    ● evict(Class arg0, Serializable arg1)将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源. 

    Java代码  收藏代码
    1. sessionFactory.evict(Customer.classnew Integer(1));  

    evict(Class arg0)将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源 
    Java代码  收藏代码
    1. sessionFactory.evict(Customer.class);  

    evictCollection(String arg0)将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源. 
    Java代码  收藏代码
    1. sessionFactory.evictCollection("Customer.orders");  


    设置一级缓存和二级缓存的交互权限 
    Java代码  收藏代码
    1. session = HibernateUtils.getSession();  
    2. session.beginTransaction();  
    3.               
    4. //仅向二级缓存读数据,而不向二级缓存写数据,这里load的数据就不会放入二级缓存,下次再查还是会去数据库拿  
    5. session.setCacheMode(CacheMode.GET);  
    6. //只向二级缓存写数据,而不从二级缓存读数据  
    7. //session.setCacheMode(CacheMode.PUT);  
    8. //不与二级缓存交互  
    9. //session.setCacheMode(CacheMode.IGNORE);  
    10. //可以与二级缓存交互  
    11. //session.setCacheMode(CacheMode.NORMAL);  
    12.   
    13. Student student = (Student)session.load(Student.class1);  
    14.   
    15. session.getTransaction().commit();  

    设置二级缓存策略 
    ● READ_ONLY:实体只读缓存 
       只读缓存不允许更新,将报错Can't write to a readonly object。 
       允许新增,(从2.0以后新增直接添加到二级缓存)
     
    Java代码  收藏代码
    1. //确保数据库中有标识符为1的FarmModel    
    2. FarmModel farm = (FarmModel) session.get(FarmModel.class1);    
    3. //如果修改将报错,只读缓存不允许修改    
    4. //farm.setName("aaa");  

    ● NONSTRICT_READ_WRITE:实体非严格读/写缓存 
       允许更新,更新后缓存失效,需再查询一次。 
       允许新增,新增记录自动加到二级缓存中。 
       整个过程不加锁。 
    ● READ_WRITE:实体读/写缓存 
       允许更新,更新后自动同步到缓存。 
       允许新增,新增记录后自动同步到缓存。 
       保证read committed隔离级别及可重复读隔离级别(通过时间戳实现) 
       整个过程加锁,如果当前事务的时间戳早于二级缓存中的条目的时间戳,说明该条目已经被别的 
       事务修改了,此时重新查询一次数据库,否则才使用缓存数据,因此保证可重复读隔离级别。 
       读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁 
    ● TRANSACTIONAL:实体事务缓存 
       缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境 
    ● Collection集合缓存
     
    Java代码  收藏代码
    1. <hibernate-mapping>  
    2.     <class name="cn.java.test.model.UserModel" table="TBL_USER">  
    3.         <cache usage="read-write" />  
    4.         <set name="farms" cascade="all" inverse="true" lazy="false">  
    5.             <cache usage="read-write"/>  
    6.             <key column="fk_user_id"/>  
    7.             <one-to-many class="cn.java.test.model.FarmModel"/>  
    8.         </set>  
    9.     </class>  
    10. </hibernate-mapping>  


    和实体并发策略有相同含义; 
    但集合缓存只缓存集合元素的标识符,在二级缓存中只存放相应实体的标识符,然后再通过标识符去二级缓存查找相应的实体最后组合为集合返回 
    Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。 
    这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新 

    高速缓存区域 
    Hibernate在不同的高速缓存区域保存不同的类(实体)/集合,如果不配置区域默认都保存到“默认缓存”(defaultCache)中。 
    ●每一个区域可以设置过期策略、缓存条目大小等等。 
    ●对于类缓存,默认区域名是全限定类名,如cn.javass.h3test.model.UserModel。 
    ●对于集合而言,默认区域名是全限定类名+属性名,如cn.javass.….UserModel.farms。 
    ●可通过hibernate.cache.region_prefix指定特定SessionFactory的区域前缀,如前缀是h3test,则如类缓存的区域名就是h3test.cn.javass.h3test.model.UserModel。如果应用程序使用多个SessionFactory这可能是必须的。 
    可通过<cache usage="read-write" region="区域名"/>自定义区域名,不过默认其实就可以了。 

    一些对二级缓存的理解 
    当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢? 
    hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。 
    当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。 
    如果找到的时间戳晚于高速缓存查询结果的时间戳,那么缓存结果将被丢弃,重新执行一次查询。 
    可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。 

    使用二级缓存的前置条件 
    对于那些查询非常多但插入、删除、更新非常少的应用程序来说,查询缓存可提升性能。但写入多查询少的没有用,总失效。 
    hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。 
    你操作数据库必需直接通过hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。 
    这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化。 
    当然可以用SessionFactory提供的移除缓存的方法(上面的二级缓存的管理里面有介绍) 

    总结 
    不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。 

    如果受不了Hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧! 
    在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧! 

    转载于:https://www.cnblogs.com/baobeiqi-e/p/9884819.html

    展开全文
  • Hibernate二级缓存原理

    2019-10-08 16:44:52
    缓存:缓存是什么,解决什么问题?位于速度相差较大的两种...事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的生命周期依...
  • Hibernate 二级缓存

    2015-05-28 18:59:16
    缓存:缓存是什么,解决什么问题?...事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事...
  • Hibernate 二级缓存配置

    2017-06-26 12:05:29
    缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的
  • hibernate二级缓存配置

    2017-04-12 22:29:16
    缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种硬件...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的
  • hibernate4之二级缓存

    2015-10-27 11:00:48
    缓存:缓存是什么,解决什么问题? 位于速度相差较大的两种...1.事务范围(单Session即一级缓存)  事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的生命周期
  • hibernate二级缓存作用、配置

    千次阅读 2017-08-09 17:45:02
    缓存:缓存是什么,解决什么问题? ...1.事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的生命周期依
  • 缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种硬件...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的
  • 缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的
  • 缓存:缓存是什么,解决什么问题?...事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生...
  • Hibernate 二级缓存 收集、总结整理

    千次阅读 2015-01-05 13:02:31
    缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种硬件/...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓
  • 缓存:缓存是什么,解决什么问题?  位于速度相差较大的两种...1.事务范围(单Session即一级缓存)   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存的数据通常采用相互关联的对象形式.缓存的
  • 缓存

    2016-07-31 13:53:26
     ## 缓存 ## 什么是缓存:缓存就是数据库在内存中的临时容器 位于数据库与数据库访问层中间 ORM在查询数据时首先会根据自身的...一级缓存:即在当前事务范围的数据缓存,就hibernate而言,一级缓存是基于s
  • Hibernate缓存

    2008-05-27 16:47:00
     Hibernate缓存分类:Hibernate缓存我们通常分两类,一类称为一级缓存也叫内部缓存,另一类称为二级缓存。Hibernate的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢?为了...

空空如也

空空如也

1 2 3 4
收藏数 71
精华内容 28
关键字:

一级缓存位于什么内