20.session的一级缓存

1.什么是缓存?

缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能。Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做缓存命 中"),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗。

 

2.Hibernate缓存分类:

一、Session缓存(又称作事务缓存):Hibernate内置的,不能卸除。

缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。

 

二、SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔。

缓存范围:缓存被应用范围内的所有session共享,不同的Session可以共享。这些session有可能是并发访问缓存,因此必须对缓存进行更新。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。

缓存策略提供商:

提供了HashTable缓存,EHCacheOSCacheSwarmCachejBoss Cathe2,这些缓存机制,其中EHCacheOSCache是不能用于集群环境(Cluster Safe)的,而SwarmCachejBoss Cathe2是可以的。HashTable缓存主要是用来测试的,只能把对象放在内存中,EHCacheOSCache可以把对象放在内存(memory)中,也可以把对象放在硬盘(disk)上(为什么放到硬盘上?上面解释了)。

 

 

session缓存:

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

   2session一级缓存存放的数据都是私有数据

        把session存放在threadlocal中,不同的线程是不能访问的,所以保证了数据的安全性

   3、怎么样把数据存放到一级缓存中

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

   4、利用session.get/load方法可以把数据从一级缓存中取出

   5session.evict方法可以把一个对象从一级缓存中清空

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

   7、利用session.Refresh方法把数据库中的数据同步到缓存中

   8session.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 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、数据能公开,私密性不是很强

   2hibernate本身并没有提供二级缓存的解决方案

(1.hibernate中二级缓存用的不多,如果数据跟新频繁,是不会放入二级缓存之中不会提高效率,2.如果不用跟新,直接和数据库交互3.因为是公有数据,每个线程访问还有加密?不懂  )

   3、二级缓存的实现是依赖于第三方供应商完成的

         ehcache

         oscache

         jbosscache

         swamchache

   4、二级缓存的操作

         1、二级缓存存在sessionFactory

         2、生命周期:与sessionFactory保持一致(容器启动sessionFactory产生,容器关闭sessionFactory关闭)

         3、使用二级缓存的步骤

             1、在hibernate.cfg.xml

                  true

                  

                        org.hibernate.cache.EhCacheProvider

                  

             2、让某一个对象进入到二级缓存中

                 * 在配置文件中

                   

                 *  在映射文件中

                    

             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">trueproperty>

  @Test
public void testQuery(){
    Session session = sessionFactory.openSession();
    Query query = session.createQuery("from Classess");
    query.setCacheable(true);//Classess里的所有的数据要往查询缓存中存放了
    List ClassessList = query.list();
    query = session.createQuery("from Classess");//查询缓存中的数据,sql语句必须和缓存的数据一致,才能利用查询缓存
    query.setCacheable(true);//取出缓存数据
    ClassessList = query.list();
    session.close();
}

  


 6.大量数据缓存

    在src下添加一个配置文件ehcache.xml


         
    
    
            
   

@Test
public void testAllClassess(){
    Session session = sessionFactory.openSession();
    List ClassessList = session.createQuery("from Classess").list();
    session.close();
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
}