hibernate--一级和二级缓存(使用Ehcache)以及查询缓存

有一下几点需要理清才行:

一级缓存是session缓存 session关闭就小时

二级缓存是sessionFactory级别的缓存 一个应用程序只有一个 多个线程共享  不要把经常修改的对象放到二级缓存中 二级缓存中放一些查询的对象

1 首先是在hibernate,cfg.xml文件中进行配置:

添加下列配置项

                <property name="hibernate.cache.use_second_level_cache">true</property>
		<!-- 使用哪种缓存提供的类 哪种缓存 -->
		<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
		<!-- 使用查询缓存-->
		<property name="hibernate.cache.use_query_cache">true</property>
		<!-- ehcache.xml的配置文件路径 -->
		<property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>
在需要使用二级缓存的对象配置文件上:

	<class name="Student" table="t_stu">
		<!--  <cache usage="read-only" /> -->
		<id name="id">
			<generator class="native"></generator>
		</id>
		<!-- 注意:version 一定要加在ID后面 property前面 -->
		<version name="version" />
		<property name="name" />
		<property name="sex" />
		<many-to-one name="classroom" column="cid" fetch="join" />
	</class>
ehcache.xml中的配置:

    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

<!-- 每一个独立的cache可以单独为不同的对象进行设置 如果找不到就用默认的cache-->
    <cache name="com.itany.model.Student"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />



2 N+1问题

 如果使用iterator返回列表 对于hibernate而言 
         它仅仅是查询了id列表的SQL 在进行iterator迭代的时候 
         再会根据id一个个去数据库查询具体对象 因此发出多条SQL 这就是典型的N+1问题 避免它
         就是不使用iterator iterator存在的原因 
         使用的地方:
         因为有可能需要查询2次 第一次list全部查询出来 存在二级缓存中 第二次 用Iterator数据库查id,再根据ID从二级缓存的对象中查询更快

            session = HibernateUtil.openSession();
            Iterator<Student> it = session.createQuery("from Student").setFirstResult(0).setMaxResults(12).iterate();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
3  重要:二级缓存缓存的是对象  查询缓存缓存的是ID 这是两种不同的缓存  谁也不依赖谁   查询缓存也是sessionFactory级别的缓存

     查询缓存是针对HQL语句的缓存  查询缓只缓存ID 而不会缓存对象
     1 但是使用查询缓存最好打开二级缓存 因为在查询缓存中查到ID后可以直接去
     二级缓存中查找 不然的话又是N+1问题 多次根据查询缓存中的ID去数据库查询
     2 若打开了二级缓存 但是没有打开查询缓存(HQL不一致、参数不一致、查询缓存没开、
     setCacheable(true)没写等原因)那么还是会直接从数据库中查询一次、
     因为需要借助查询缓存查ID再到二级缓存中查对象
     3 注意:load方式可以直接从二级缓存中查对象 不必借助查询缓存
     4如果取得只是某些属性(而不是完整对象) 那么不会进行二级缓存见test04
     5 查询缓存 工作顺序:如果正常开启了查询缓存(HQL完全一致 且set(True)),先去查询缓存中查ID
          再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
         若二级缓存没打开  那么此时会再次根据查到的ID去数据库中查询

4 代码中使用查询缓存

  

 List<Object[]> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存  查询缓存也是sessionFactory级别的缓存
5 此时关闭了二级缓存(存对象)
    打开了查询缓存(存ID) 第二个人查询缓存只查到ID 会根据ID 去二级缓存查对象  但是没有  所以去数据库查  发出大量SQL

6 查询缓存很少使用 因为很少HQL完全一样
          因为只要HQL语句不一样 就不会开启查询缓存 
          只有两个完全一样的 并且参数都一样的 才能使用查询缓存

public class TestSecondCache
{
    /*
     * 重要:二级缓存缓存的是对象  查询缓存缓存的是ID 这是两种不同的缓存
     * 谁也不依赖谁  
     * 1 但是使用查询缓存最好打开二级缓存 因为在查询缓存中查到ID后可以直接去
     * 二级缓存中查找 不然的话又是N+1问题 多次根据查询缓存中的ID去数据库查询
     * 2 若打开了二级缓存 但是没有打开查询缓存(HQL不一致、参数不一致、查询缓存没开、
     * setCacheable(true)没写等原因)那么还是会直接从数据库中查询一次、
     * 因为需要借助查询缓存查ID再到二级缓存中查对象
     * 3 注意:load方式可以直接从二级缓存中查对象 不必借助查询缓存
     * 
     * 如果取得只是某些属性(而不是完整对象) 那么不会进行二级缓存见test04
     */
    
    @Test
    public void test01()
    {
        /*
         * 不可以缓存 Ehcache是看SQL是否一样
         */
        Session session = null;
        try
        {
            session = HibernateUtil.openSession();
            Student s=(Student)session.load(Student.class,1);
            System.out.println(s.getName());
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        Session session2 = null;
        /*
         * 此时session已经关闭 但再次查询 仍然可以不发SQL  二级缓存起作用了
         */
        try
        {
            session2 = HibernateUtil.openSession();
            Student s2=(Student)session2.load(Student.class,1);//这种写法 根据ID去二级缓存中查询
            System.out.println(s2.getName());
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session2)
                HibernateUtil.closeSession(session2);
        }
    }
    @Test
    public void test02()
    {
        /*
         * 
         */
        Session session = null;
        try
        {
            session = HibernateUtil.openSession();
            Student s=(Student)session.load(Student.class,1);
            System.out.println(s.getName());
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        Session session2 = null;
        Transaction trans=null;
        /*
         * 会报错 因为二级缓存 在Student上设置的是 read-only 因此不能写入
         * 最好不要设置 read write因为hibernate要频繁的加锁 解锁 影响效率 还不如不用二级缓存
         */
        try
        {
            session2 = HibernateUtil.openSession();
            trans=session2.beginTransaction();
            Student s2=(Student)session2.load(Student.class,1);
            s2.setName("zhangasnsss");
            System.out.println(s2.getName());
            trans.commit();
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session2)
                HibernateUtil.closeSession(session2);
        }
    }
    @Test
    public void test03()
    {
        /*
         * 
         */
        Session session = null;
        Transaction trans = null;
        try
        {
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("from Student").list();
            Iterator<Student> it = ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        
        try
        {
            session = HibernateUtil.openSession();
            Student s=(Student)session.load(Student.class,1);
            System.out.println(s.getName());
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test04()
    {
        /*
         * 
         */
        Session session = null;
        Transaction trans = null;
        try
        {
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu.id,stu.name from Student stu").list();
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /*
         * 以上代码仅仅去了id和name 而二级缓存是缓存对象的 所以上一段代码不会使用二级缓存
         * 此时就会发出相应的SQL
         */
        try
        {
            session = HibernateUtil.openSession();
            Student s=(Student)session.load(Student.class,1);
            System.out.println(s.getName());
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test05()
    {
        /*
         * iterator 作用就是配合二级缓存使用 最好
         */
        Session session = null;
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu").list();
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /* 1条SQL
         * 由于学生的对象经过上面查询对象之后 已经存在于二级缓存之中
         * 此时正好直接使用iterator  首先会查询通过1条取ID的语句  然后再获取对象时候去二级缓存中查询
         * 有的话 直接用 不会产生N+1问题
         * 
         *    若没二级缓存 我们直接使用iterator会首先产生一条查ID的语句
         *    再在获取对象的时候再去数据库中取 那么这是就会产生N+1问题
         */
        try
        {
            session = HibernateUtil.openSession();
            Iterator<Student> it = session.createQuery("from Student").iterate();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test06()
    {
        /*
         * 与上面一个几乎一样 区别在于iterator换成list() 
         * 虽然第一次已经二级缓存了  但是不能决定我再去不去数据库中查询
         * 
         * 重要 :如果希望第二次不发SQL 那就要使用查询缓存
         * 查询缓存是针对HQL语句的缓存  查询缓只缓存ID 而不会缓存对象
         */
        Session session = null;
        
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu").list();
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /* 1条SQL  和上一条一模一样
         * 
         */
        try
        {
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("select stu  from Student stu").list();
            Iterator<Student> it=ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test07()
    {
        /*
         * 设置了查询缓存为true
         */
        Session session = null;
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu")
                .setCacheable(true).list();//开启查询缓存  查询缓存也是sessionFactory级别的缓存
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /*0条SQL 
         * 
         */
        try
        {
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("select stu  from Student stu")
                .setCacheable(true).list();
            Iterator<Student> it=ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test08()
    {
        /*
         * 此时无法使用查询缓存 查询缓存很少使用 因为很少HQL完全一样
         * 因为只要HQL语句不一样 就不会开启查询缓存 
         * 只有两个完全一样的 并且参数都一样的 才能使用查询缓存
         */
        Session session = null;
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存  查询缓存也是sessionFactory级别的缓存
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /*
         * 
         */
        try
        {
          //一条SQL
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%王%").list();
            Iterator<Student> it=ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test09()
    {
        /*
         * 此时关闭了二级缓存(存对象)
         * 打开了查询缓存(存ID)
         * !!!工作顺序:如果正常开启了查询缓存(HQL完全一致 且set(True)),先去查询缓存中查ID
         * 再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
         * 若二级缓存没打开  那么此时会再次根据查到的ID去数据库中查询
         */
        Session session = null;
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存  查询缓存也是sessionFactory级别的缓存
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /*
         * 
         */
        try
        {
          //此时关闭了student的二级缓存 打开了查询缓存 发出大量SQL
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();
            Iterator<Student> it=ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test10()
    {
        /*
         * 此时打开了二级缓存(存对象)
         * 打开了查询缓存(存ID)
         * !!!!工作顺序:如果正常开启了查询缓存,先去查询缓存中查ID
         * 再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
         * 若二级缓存没打开  那么此时会再次根据查到的ID去数据库中查询
         */
        Session session = null;
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存  查询缓存也是sessionFactory级别的缓存
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /*
         * 
         */
        try
        {
          //此时打开了student的二级缓存 打开了查询缓存 不发SQL
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();
            Iterator<Student> it=ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
    @Test
    public void test11()
    {
        /*
         * 此时打开了二级缓存(存对象)
         * 打开了查询缓存(存ID)
         * !!!!工作顺序:如果正常开启了查询缓存,先去查询缓存中查ID
         * 再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
         * 若二级缓存没打开  那么此时会再次根据查到的ID去数据库中查询
         */
        Session session = null;
        Transaction trans = null;
        try
        {   //一条SQL
            session = HibernateUtil.openSession();
            List<Object[]> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存  查询缓存也是sessionFactory级别的缓存
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
        /*
         * 
         */
        try
        {
          //此时虽然打开了student的二级缓存 但是不能使用查询缓存(HQL不一致)导致没法通过查询缓存查ID去
           //二级缓存中查对象
          //所以仍然发出一条SQL 从数据库中查询
            session = HibernateUtil.openSession();
            List<Student> ls = session.createQuery("select stu  from Student stu where name like ?")
                .setCacheable(true).setParameter(0, "%张三%").list();
            Iterator<Student> it=ls.iterator();
            while (it.hasNext())
            {
                Student stu = it.next();
                System.out.println(stu.getName());
            }
        }
        catch (HibernateException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != session)
                HibernateUtil.closeSession(session);
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值