Hibernate框架之二级缓存

二级缓存是SessionFactory级别的缓存, 是一种进程级别的缓存, 这个缓存可以跨session

生命周期跟SessionFactory周期一样, 如果关闭SessionFactory, 则二级缓存消失

二级缓存跟一级缓存的相同点在于同样只能缓存实体对象而不能缓存属性

适合使用二级缓存:

数据比较少改动(经常被读, 很少修改)

数据不是很重要, 只是偶尔的并发

参考数据

不适合使用二级缓存:

经常要修改的数据

财务数据, 绝对不允许并发问题的出现

和其他的环境的数据做共享的数据

第三方的二级缓存产品: ehcache

支持在内存和硬盘上做存储/支持集群/支持查询缓存

 

第一步: 引入"ehcache.xml"配置文件: 链接:https://pan.baidu.com/s/1w4KIHdqpdWYkw9sxLQSz9A 密码:0km5

第二步: 开启二级缓存的配置的总开关:

"hibernate.cfg.xml"配置文件:

<!-- 手动开启二级缓存
		 -->
		<property name="hibernate.cache.use_second_level_cache">true</property>

此时开启的是Hibernate框架自己的二级缓存, 我们需要整合ehcache第三方的二级缓存

"hibernate.cfg.xml"配置文件:

<!-- 配置整合ehcache的二级缓存
		 -->
		<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

ehcache的配置说明:

属性说明
maxElementsInMemory缓存中对象的个数(缓存的大小)
eternal缓存中的对象是否用久有效(一般都不会设置成永久有效)
timeToIdleSecond对象失效前允许的闲置时间
timeToLiveSecond对象在缓存中存在的最大时间
overFlowToDisk如果缓存已满, 则可以写在硬盘上
maxElementsOnDisk对象在硬盘上的最大数量
diskPersisent对象在硬盘上是否永久有效(一般不用设置)
memoryStoreEvictionPolicy①LRC(最近最少使用)   ②FIFO(先进先出)

第二步: 对具体的对象开启二级缓存:

"User.hbm.xml"配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 
package:指定当前映射文件的实体类model所在的包
 -->
<hibernate-mapping package="com.rl.hiber.model">

	<class name="User" table="t_user">
	
	<!-- 对具体的user对象开启二级缓存
	 -->
	<cache usage="read-only"/>
		<!-- id
			是主键映射配置
		 -->
		<id name="userId" column="user_id">
			<!-- 
				generator:主键的映射策略
			 -->
			<generator class="native"></generator>
		</id>
		<property name="uname"></property>
		<property name="gender"></property>
		<property name="birthday"></property>
	</class>
</hibernate-mapping>

测试代码:

package com.rl.hiber.test;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtils;

public class TestHibernate3 {
    
    /**
     * 二级缓存跨session
     * get和load方法都能支持二级缓存
     */
    @Test
    public void query1(){
        
        Session session = HibernateUtils.getSession();
        
        try {
            User user = (User)session.get(User.class, 1);
//            User user = (User)session.load(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeSession(session);
        }
        
        Session session2 = HibernateUtils.getSession();
        try {
            User user = (User)session2.get(User.class, 1);
//            User user = (User)session2.load(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeResource(session2);
        }
    }
    
    /**
     * list不使用二级缓存
     */
    @Test
    public void query2(){
        Session session = HibernateUtils.getSession();
        try {
            Query query = session.createQuery("from User");
            List<User> userList = query.list();
            for(User user: userList){
                System.out.println(user);
            }
        } finally{
            HibernateUtils.closeSession(session);
        }
        
        Session session2 = HibernateUtils.getSession();
        try {
            Query query = session2.createQuery("from User");
            List<User> userList = query.list();
            for(User user: userList){
                System.out.println(user);
            }
        } finally{
            HibernateUtils.closeResource(session2);
        }
    }
    
    /**
     * iterate方法使用二级缓存
     * 先查出所有id, 再根据每个id具体查询
     */
    @Test
    public void query3(){
        Session session = HibernateUtils.getSession();
        try {
            Query query = session.createQuery("from User");
            Iterator<User> iterator = query.iterate();
            while(iterator.hasNext()){
                User user = iterator.next();
                System.out.println(user);
            }
        } finally{
            HibernateUtils.closeSession(session);
        }
        
        Session session2 = HibernateUtils.getSession();
        try {
            Query query = session2.createQuery("from User");
            Iterator<User> iterator = query.iterate();
            while(iterator.hasNext()){
                User user = iterator.next();
                System.out.println(user);
            }
        } finally{
            HibernateUtils.closeResource(session2);
        }
    }
}

二级缓存的策略:

二级缓存的策略有<cache>中的usage属性来控制

read-only: 只读缓存, 二级缓存中的数据无法修改

nonstrict-read-write: 允许更新数据库, 一旦更新则二级缓存中的相对应的数据会被清空, 重新查询的话则需要重新发出sql; 但是新增数据则不会清掉二级缓存的数据, 重新查询不会发出sql也能查询到新增的最新数据

read-write: 允许更新数据库, 一旦更新, 二级缓存的数据也会被同步更新, 重新查询则不需要发出sql也能查询到最新的数据

测试代码:

package com.rl.hiber.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtils;

public class TestHibernate4 {
    
    /**
     * usage: read-only
     */
    @Test
    public void query1(){
        
        Session session = HibernateUtils.getSession();
        
        try {
            User user = (User)session.get(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeSession(session);
        }
        
        Session session2 = HibernateUtils.getSession();
        Transaction tx = session2.beginTransaction();
        try {
            //不发出sql, 从二级缓存中读取数据
            User user = (User)session2.get(User.class, 1);
            System.out.println(user);
            user.setUname("周八");
            session2.update(user);
            //提交时报错, 因为二级缓存配置为只读, 不允许被修改
            tx.commit();
        } catch(Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeResource(session2);
        }
    }
    
    /**
     * usage: nonstrict-read-write
     */
    @Test
    public void query2(){
        
        Session session2 = HibernateUtils.getSession();
        Transaction tx = session2.beginTransaction();
        try {
            //发出查询sql
            User user = (User)session2.get(User.class, 1);
            System.out.println(user);
            user.setUname("周八");
            session2.update(user);
            //nonstrict-read-write的策略是此时发出修改数据库的sql, 并同步清空二级缓存的user对象
            tx.commit();
        } catch(Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session2);
        }
        
        Session session = HibernateUtils.getSession();
        try {
            //由于二级缓存的user对象被清空, 所有必须重新发送sql
            User user = (User)session.get(User.class, 1);
            //输出查询的数据
            System.out.println(user);
        } finally{
            HibernateUtils.closeResource(session);
        }
    }
    
    /**
     * usage: read-write
     */
    @Test
    public void query3(){
        
        Session session2 = HibernateUtils.getSession();
        Transaction tx = session2.beginTransaction();
        try {
            //发出查询sql
            User user = (User)session2.get(User.class, 1);
            System.out.println(user);
            user.setUname("陈二");
            session2.update(user);
            //read-write策略是此时发出修改数据库的sql, 并同步更新二级缓存的user对象
            tx.commit();
        } catch(Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session2);
        }
        
        Session session = HibernateUtils.getSession();
        try {
            //不发出sql
            User user = (User)session.get(User.class, 1);
            //输出更新后的数据
            System.out.println(user);
        } finally{
            HibernateUtils.closeResource(session);
        }
    }
}

二级缓存的手动管理:

测试代码:

package com.rl.hiber.test;

import org.hibernate.CacheMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtils;

public class TestHibernate5 {
    
    @Test
    public void query1(){
        
        Session session = HibernateUtils.getSession();
        
        try {
            //发出sql
            User user = (User)session.get(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeSession(session);
        }
        //获取SessionFactory对象
        SessionFactory sf = HibernateUtils.getSessionFactory();
        //将指定的user逐出
        sf.getCache().evictEntity(User.class, 1);
        
        Session session2 = HibernateUtils.getSession();
        try {
            //需要重新发出sql
            User user = (User)session2.get(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeResource(session2);
        }
    }
    
    @Test
    public void query2(){
        
        Session session = HibernateUtils.getSession();
        try {
            //设置session一级缓存的数据只能从二级缓存中读,不能向二级缓存中写
            session.setCacheMode(CacheMode.GET);
            //发出sql
            User user = (User)session.get(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeSession(session);
        }
        
        Session session2 = HibernateUtils.getSession();
        try {
            //由于二级缓存中没有user的数据, 所以只能重新发出sql
            User user = (User)session2.get(User.class, 1);
            System.out.println(user);
        } finally{
            HibernateUtils.closeResource(session2);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值