Hibernate 缓存

Hibernate缓存

 后台取数据过程是:
  先判断缓存里有没有数据,如果有从缓存里取数据让后返回,如果缓存里没有数据,则从数据库中取让后把数据存进缓存
  使用缓存可以大幅度的提高查询速度和程序响应速度
  有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!

1、hibernate一级缓存

       一级缓存也叫Session的缓存,不能跨Session,如果Session关闭那么数据也清掉。
     (  一级缓存只能缓存实体对象,不能缓存属性

1.1 model 实体类

              我们以User表做例子
package model;

import java.util.Date;

public class User {
    private Integer userId;
    private String userName;
    private Integer gender;
    private Date birthday;
    private String address;

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", gender=" + gender +
                ", birthday=" + birthday +
                ", address='" + address + '\'' +
                '}';
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

1.2 配置映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="model">
    <class name="model.User" table="t_user">
        <id name="userId" column="user_id">
            <generator class="native"/>
        </id>
        <property name="userName" column="user_name"/>
        <property name="gender"/>
        <property name="birthday"/>
        <property name="address"/>
    </class>
</hibernate-mapping>

1.3测试类

        User  user = (User) session.load(User.class, 1);
        //发出sql(从数据库中查询数据 然后存到session中)
        System.out.println(user);
        //不发出sql
        User  user1= (User) session.load(User.class, 1);
        System.out.println(user1);
       从这段程序可知第一次是从数据库中取数据,第二次是从session中取数据
        (get   load iterator 都使用一级缓存 list不使用一级缓存)
        【一级缓存只能在一个session中不能跨session】
        (修改持久对象后一级缓存也会被同步更新,查询时不发sql)
        (save和update都会对一级缓存有刷新作用)
                    一级缓存的管理使用evict 和clear
         //把user从一级缓存中逐出
        session.evict(user);
         //清理缓存
        session.clear();
 @Test
    public void initData() {
        Session session = HibernateUtils.getSession();
        Transaction ts = session.beginTransaction();
        try {

            for (int i = 0; i <1000; i++) {
                User user = new User();
                if (i % 2 == 0) {
                    user.setUserName("张豆豆");
                    user.setGender(0);
                    user.setBirthday(new Date());
                    user.setAddress("天水");
                } else {
                    user.setUserName("周志强");
                    user.setGender(1);
                    user.setBirthday(new Date());
                    user.setAddress("天水");
                }
                session.save(user);
            }
            ts.commit();
        } catch (Exception e) {
            e.printStackTrace();
            ts.rollback();
        }finally {
            HibernateUtils.closeResource(session);
        }
    }

    @Test
    public void testFetch() {
        Session session = HibernateUtils.getSession();
        try {
            User  user = (User) session.load(User.class, 1);
            //发出sql(从数据库中查询数据 然后存到session中)
            System.out.println(user);
            //不发出sql
            User  user1= (User) session.load(User.class, 1);
            System.out.println(user1);
             //把user从一级缓存中逐出
            session.evict(user);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            HibernateUtils.closeResource(session);
        }
    }

2、hibernate二级缓存(对ehcache的说明)

2.1二级缓存简介

         二级缓存是SessionFactory级别的缓存,这个缓存能被所有的session共享,
        可以跨session,如果SessionFactory关闭,二级缓存随着消失。
         二级缓存也是只缓存实体对象,不能对普通属性做缓存
         后台取数据还是遵从缓存机制,先从一级缓存中找,
         如果没有就从二级缓存中找(二级缓存开启),如果还没有就从数据库中找
         顺便把数据备份到一级缓存和二级缓存中,同时会更新一级缓存

2.2二级缓存应用场景

        适合使用二级缓存:
        数据很少被修改 大量的修改会产生并发问题一般在数据库端处理
        数据不是特别重要,允许偶尔的并发
        参考数据
        不适合使用二级缓存场景:
          经常要修改的数据
          财务数据,绝对不允许并发问题出现。  
          和其他环境的数据做共享的数据            

提高程序的性能
关系型数据库:数据与数据之间存在关系(联系)的数据库 mysql/Oracle、 sqlserver
非关系型数据库:数据与数据之间是不存在关系的,key-value
1、基于文件存储的数据库:ehcache
2、基于内存存储的数据库:redis、memcache
3、基于文档存储的数据库:mongodb

2.3 二级缓存配置(第三方二级缓存Ehcache)

            支持在内存和硬盘上做缓存,可以支持集群,可以至此查询缓存。
2.3.1Ehcache配置文件 ehcache.xml(必须导入到项目中)
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />
    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        />
</ehcache>
           属性                                    说明
           maxElementsInMemory   缓存中对象的个数 
           eternal                           elements是否永久有效
           TimeToldSecond          在对象失效前允许的闲置时间(也就是对象不用它就失效)
           TimeToLiveSecond        对象在缓存中存在的最大时间
           OverFlowToDisk         如果内存缓存满了就可以写在硬盘上
           MaxElementsOndisk  硬盘上的对象的最大数量
           diskPersistent            是否在硬盘上永久有效
           memoryStoreEvictionPolicy  内存中对象的逐出策略   LRC(最近最少使用) FIFO(先进先出)
2.3.2Hibernate.cfg.xml配置文件中对ehcache的配置
       一般报错为初始化错误大多情况是配置文件出现,
       而且更大可能性是核心配置文件出错。切记切记

        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!--开启二级缓存-->
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <!--指定使用哪一个缓存框架(整合Ehtch)-->
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
2.3.3二级缓存在映射文件上的配置
  <!--对当前user对象开启二级缓存,并且设置usage缓存策略-->
    <cache usage="read-only"/>
     
     二级缓存缓存策略usage
     read-only 只读缓存 只能读不能修改
     nonstrict-read-write:不严格的读写,允许更新。
     一旦更新数据库中的数据相应的二级缓存中的数据就被清掉了
     (不是清掉所有而是清掉当前操作的对象)
     再次做同样查询就会重新发出sql语句。
     (往二级缓存存数据不会清掉二级缓存)
     这种策略适合于不是经常性的更新
     在工作中这种缓存策略用的比较多
     read-write:读写型,缓存在数据变化时触发更新,适用于变化的数据,
     transactional:支持事务的缓存(了解)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="model">
    <class name="model.User" table="t_user">
        <!--对当前user对象开启二级缓存,并且设置缓存策略 usage-->
        <cache usage="read-only"/>
        <id name="userId" column="user_id">
            <generator class="native"/>
        </id>
        <property name="userName" column="user_name"/>
        <property name="gender"/>
        <property name="birthday"/>
        <property name="address"/>
    </class>
</hibernate-mapping>

2.4测试类

      充分说明了二级缓存是跨session的
      get load  iterator都是可以使用二级缓存的
      list不使用二级缓存  
     哪些方法可以使用二级缓存哪些不使用二级缓存和一级缓存中一样
    @Test
    public void testFetch() {
        Session session = HibernateUtils.getSession();
        try {
            User user = (User) session.load(User.class, 4);
            //发出sql
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            HibernateUtils.closeSession(session);
        }
        Session session1 = HibernateUtils.getSession();
        try {
            User user = (User) session1.load(User.class, 4);
            //不发出sql
            System.out.println(user);
        } catch (Exception e) {
           e.printStackTrace();
        }finally {
            try {
                HibernateUtils.closeResource(session);
            } catch (Exception e) {
                if (e instanceof org.hibernate.SessionException) {
                    System.out.println("出现了一个小问题正在处理");
                }
            }
        }
    }

2.5手动管理二级缓存

          //获得session工厂
    SessionFactory sf = HibernateUtils.getsessionFactory();
    //获得二级缓存
    Cache cache = sf.getCache();
    //从二级缓存中清理对象
    cache.evictEntity(User.class,4);
//获得session工厂
        SessionFactory sf = HibernateUtils.getsessionFactory();
        //获得二级缓存
        Cache cache = sf.getCache();
        //从二级缓存中清理对象
        cache.evictEntity(User.class,4);

2.6一级缓存和二级缓存的交互

             //设置session一级缓存的数据只能从二级缓存中读,
             不能往二级缓存里写
        session.setCacheMode(CacheMode.GET);
//设置session一级缓存的数据只能从二级缓存中读,不能往二级缓存里写
            session.setCacheMode(CacheMode.GET);

3、hibernate查询缓存

           查询缓存可以缓存基本属性,它也可以对实体对象缓存id;
           查询缓存的生命周期,一旦查询的数据库的表被修改,缓存就清掉
           查询缓存也需要开启

3.1开启查询缓存

           <!--开启查询缓存-->
<property name="hibernate.cache.use_query_cache">true</property>
<!-- Disable the second-level cache  -->
    <!--开启二级缓存-->
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <!--指定使用哪一个缓存框架(整合Ehtch)-->
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    <!--开启查询缓存-->
    <property name="hibernate.cache.use_query_cache">true</property>

3.2测试类

     查询缓存也是跨session的
      //开启查询缓存
        query.setCacheable(true);
        list 和uniqueResult  支持查询缓存
        iterator 支持查询缓存
    @Test
    public void testQuery() {
        Session session = HibernateUtils.getSession();
        try {
            String hql = "select u.userName,gender from User u where u.userId=?";
            Query query = session.createQuery(hql);
            //开启查询缓存
            query.setCacheable(true);
            query.setParameter(0,3);
            List<Object[]> aList = query.list();
            //发出查询sql语句
            for (Object[] object : aList) {
                System.out.println("姓名:" + object[0] + "  性别:" + object[1]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            HibernateUtils.closeSession(session);
        }
        Session session1 = HibernateUtils.getSession();
        try {
            String hql = "select u.userName,gender from User u where u.userId=?";
            Query query = session1.createQuery(hql);
            //开启查询缓存
            query.setCacheable(true);
            query.setParameter(0,3);
            List<Object[]> aList = query.list();
            //不发出查询sql直接从查询缓存中取数据
            for (Object[] object : aList) {
                System.out.println("姓名:" + object[0] + "  性别:" + object[1]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                HibernateUtils.closeResource(session);
            } catch (Exception e) {
                if (e instanceof org.hibernate.SessionException) {
                    System.out.println("问题不大也就是小问题");
                }
            }

        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值