天天看點

hibernate緩存

20.session的一級緩存

1.什麼是緩存?

緩存是介于實體資料源與應用程式之間,是對資料庫中的資料複制一份臨時放在記憶體中的容器,其作用是為了減少應用程式對實體資料源通路的次數,進而提高了應用程式的運作性能。Hibernate在進行讀取資料的時候,根據緩存機制在相應的緩存中查詢,如果在緩存中找到了需要的資料(我們把這稱做“緩存命 中"),則就直接把命中的資料作為結果加以利用,避免了大量發送SQL語句到資料庫查詢的性能損耗。

2.Hibernate緩存分類:

一、Session緩存(又稱作事務緩存):Hibernate内置的,不能卸除。

緩存範圍:緩存隻能被目前Session對象通路。緩存的生命周期依賴于Session的生命周期,當Session被關閉後,緩存也就結束生命周期。

二、SessionFactory緩存(又稱作應用緩存):使用第三方插件,可插拔。

緩存範圍:緩存被應用範圍内的所有session共享,不同的Session可以共享。這些session有可能是并發通路緩存,是以必須對緩存進行更新。緩存的生命周期依賴于應用的生命周期,應用結束時,緩存也就結束了生命周期,二級緩存存在于應用程式範圍。

緩存政策提供商:

提供了HashTable緩存,EHCache,OSCache,SwarmCache,jBoss Cathe2,這些緩存機制,其中EHCache,OSCache是不能用于叢集環境(Cluster Safe)的,而SwarmCache,jBoss Cathe2是可以的。HashTable緩存主要是用來測試的,隻能把對象放在記憶體中,EHCache,OSCache可以把對象放在記憶體(memory)中,也可以把對象放在硬碟(disk)上(為什麼放到硬碟上?上面解釋了)。

session的緩存:

   1、生命周期就是session的生命周期

   2、session一級緩存存放的資料都是私有資料

        把session存放在threadlocal中,不同的線程是不能通路的,是以保證了資料的安全性

   3、怎麼樣把資料存放到一級緩存中

        利用session.save/update/load/get方法都可以存放在一級緩存中

   4、利用session.get/load方法可以把資料從一級緩存中取出

   5、session.evict方法可以把一個對象從一級緩存中清空

   6、利用session.clear方法可以把session中的所有的資料清空

   7、利用session.Refresh方法把資料庫中的資料同步到緩存中

   8、session.flush

        在session的緩存内部,會去檢查所有的持久化對象

           1、如果一個持久化對象沒有ID值,則會發出insert語句

           2、如果一個持久化對象有ID值,則會去檢查快照進行對比,如果一樣,則什麼都不做,如果不一樣,則發出update語句

           3、檢查所有的持久化對象是否有關聯對象

                檢查關聯對象的級聯操作

                檢查關聯對象的關系操作

   9、批量操作

測試

public class SessionCacheTest extends HibernateUtils{
@Test
public void testGet(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = (Classess)session.get(Classess.class, 1L);
    Classess = (Classess)session.get(Classess.class,1L);
    transaction.commit();
}
/**
 * session.load方法把資料存放在一級緩存中
 */
@Test
public void testLoad(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = (Classess)session.load(Classess.class, 1L);
    Classess.getCname();
    Classess = (Classess)session.load(Classess.class,1L);
    Classess.getCname();
    transaction.commit();
}
/**
 * session.save方法把資料儲存在一級緩存中
 */
@Test
public void testSave(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = new Classess();
    Classess.setCname("aaa");
    Classess.setDescription("asfd");
    session.save(Classess);
    Classess = (Classess)session.get(Classess.class, Classess.getCid());
    transaction.commit();
}
/**
 * session.update
 */
@Test
public void testUpdate(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = (Classess)session.get(Classess.class, 1L);
    session.evict(Classess);//Classess對象從session中清空了
    session.update(Classess);//把Classess對象放入到了session緩存中
    Classess = (Classess)session.get(Classess.class, 1L);
    transaction.commit();
}
/**
 * session.clear
 */
@Test
public void testClear(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = (Classess)session.get(Classess.class, 1L);
    session.clear();//Classess對象從session中清空了
    Classess = (Classess)session.get(Classess.class, 1L);
    transaction.commit();
}
@Test
public void testClearTest(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess  = (Classess)session.get(Classess.class, 1L);
    session.clear();//如果不加這句話,兩個不同的對象,相同的ID值,是以得把其中的一個清空
    Classess Classess2 = new Classess();
    Classess2.setCid(1L);
    Classess2.setCname("asfd");
    session.update(Classess2);
    transaction.commit();
}
/**
 * 把資料庫中的資料重新整理到緩存中
 */
@Test
public void testRefresh(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = (Classess)session.get(Classess.class, 1L);
    Classess.setCname("66");
    session.refresh(Classess);//把cid為1的值從資料庫刷到了緩存中
    System.out.println(Classess.getCname());
    transaction.commit();
}
/**
 * session.flush
 */
@Test
public void testFlush(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess  =(Classess)session.get(Classess.class, 1L);
    Classess.setCname("afdsasdf");
    Set<Student> students = Classess.getStudents();
    for(Student student:students){
        student.setDescription("asdf");
    }
    session.flush();
    transaction.commit();
}
 
/**
 * 批量操作
 */
@Test
public void testSaveBatch(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    for(int i=6;i<1000000;i++){
        Classess Classess = new Classess();
        Classess.setCname("aaa");
        Classess.setDescription("afds");
        session.save(Classess);
        if(i%50==0){
            session.flush();
            session.clear();
        }
    }
    transaction.commit();
}
/**
 * session.flush隻是發出SQL語句了,并沒有清空session緩存
 */
@Test
public void testFlush2(){
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Classess Classess = (Classess)session.get(Classess.class, 1L);
    session.flush();
    Classess = (Classess)session.get(Classess.class, 1L);
    transaction.commit();
    }
}      

21.二級緩存

二級緩存:存放公有資料

   1、适用場合:

        1、資料不能頻繁更新

        2、資料能公開,私密性不是很強

   2、hibernate本身并沒有提供二級緩存的解決方案

(1.在hibernate中二級緩存用的不多,如果資料跟新頻繁,是不會放入二級緩存之中不會提高效率,2.如果不用跟新,直接和資料庫互動3.因為是公有資料,每個線程通路還有加密?不懂  )

   3、二級緩存的實作是依賴于第三方供應商完成的

         ehcache

         oscache

         jbosscache

         swamchache

   4、二級緩存的操作

         1、二級緩存存在sessionFactory中

         2、生命周期:與sessionFactory保持一緻(容器啟動sessionFactory産生,容器關閉sessionFactory關閉)

         3、使用二級緩存的步驟

             1、在hibernate.cfg.xml

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

                  <property name="cache.provider_class">

                        org.hibernate.cache.EhCacheProvider

                  </property>

             2、讓某一個對象進入到二級緩存中

                 * 在配置檔案中

                   <class-cache usage="read-only" class="cn.itcast.hiberate.sh.domain.Classes"/>

                 *  在映射檔案中

                    <cache usage="read-only"/>

             3、使用

                  session.get/session.load

/**
 * session.get
 *    把資料存在一級緩存和二級緩存
 */
@Test
public void testGet11(){
    Session session = sessionFactory.openSession();
    Classess Classess = (Classess)session.get(Classess.class, 1L);
    session.close();
    session = sessionFactory.openSession();
    Classess = (Classess)session.get(Classess.class, 1L);
    session.close();
}
/**
 * session.load
 *   同上
 */
@Test
public void testLoad22(){
    Session session = sessionFactory.openSession();
    Classess Classess = (Classess)session.load(Classess.class, 1L);
    Classess.getCname();
    session.close();
    session = sessionFactory.openSession();
    Classess = (Classess)session.load(Classess.class, 1L);
    Classess.getCname();
    session.close();
}
/**
 * session.update
 */
@Test
public void testUpdate11(){
    Session session = sessionFactory.openSession();
    //session.beginTransaction();
    Classess Classess = new Classess();
    Classess.setCid(1L);
    Classess.setCname("aaa");
    session.update(Classess);
    session.close();
    session = sessionFactory.openSession();
    Classess = (Classess)session.get(Classess.class, 1L);
    session.close();
}      

   5、查詢緩存

    在hibernate配置檔案添加<property name="cache.use_query_cache">true</property>

  @Test
public void testQuery(){
    Session session = sessionFactory.openSession();
    Query query = session.createQuery("from Classess");
    query.setCacheable(true);//Classess裡的所有的資料要往查詢緩存中存放了
    List<Classess> ClassessList = query.list();
    query = session.createQuery("from Classess");//查詢緩存中的資料,sql語句必須和緩存的資料一緻,才能利用查詢緩存
    query.setCacheable(true);//取出緩存資料
    ClassessList = query.list();
    session.close();
}      
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
         
    <diskStore path="D:\\TEMP1"/>
    <defaultCache
            maxElementsInMemory="12"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
            
   <Cache
            name="cn.itcast.domain.Classes"
            maxElementsInMemory="5" 
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
</ehcache>
@Test
public void testAllClassess(){
    Session session = sessionFactory.openSession();
    List<Classess> ClassessList = session.createQuery("from Classess").list();
    session.close();
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
}      

繼續閱讀