zoukankan      html  css  js  c++  java
  • Hibernate学习---第十五节:hibernate二级缓存

    1、二级缓存所需要的 jar 包

    QQ截图20150131231759

    这三个 jar 包实在 hibernate 解压缩文件夹的 liboptionalehcache 目录下

    2、配置 ehcache.xml

    <ehcache>
    
        <!-- 指定当缓存数据超出规定缓存大小的时候,超出的缓存数据写入到磁盘的位置 -->
        <diskStore path="D:/cache/tmp"/>
        <!--
            maxInMemory       - 允许在二级缓存中的持久化对象数量
            eternal           - 缓存中的持久化对象是否允许销毁  false:表示可以销毁
            timeToIdleSeconds - 当激活时间到期,持久化对象可以存活的时间(钝化时间)
            timeToLiveSeconds - 缓存中对象的激活时间(有效时间)
            overflowToDisk    - 是否允许缓存数据序列化到磁盘
        -->
        <defaultCache
            maxElementsInMemory="10"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
         />
    </ehcache>

    3、配置 hibernate.cfg.xml

    在配置文件添加如下代码:

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

    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

    具体如下:

    <!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">123456</property> 
            <property name="hibernate.hbm2ddl.auto">update</property>
            <property name="hibernate.show_sql">true</property>
            <!-- 二级缓存配置   -->
            <!-- 开启二级缓存(默认是开启二级缓存的) -->
            <property name="hibernate.cache.use_second_level_cache">true</property>
            <!-- 配置二级缓存的视实现类(第三方插件包)  以下这个缓存类的包路径是错误的
            <property name="hibernate.cache.region.factory_class">org.hibernate.cache.internal.EhCacheRegionFactory</property> -->
            <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
            <mapping resource="learnhibernateeanPerson.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>

    4、支持二级缓存持久化类配置,有两种配置方式

    第一种在持久化配置文件中配置:

    <?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">
    <hibernate-mapping package="learn.hibernate.bean">    
        <class name="Person" table="t_person">
            <!-- 配置持久化类支持二级缓存的读写操作 -->
            <cache usage="read-write"/>
            <id name="id" column="person_id">
                <generator class="native"/>
            </id>
            <property name="name" column="t_name"/>
            <property name="age"/>    
            <property name="passwork"/>
            <property name="birthday"/>
        </class>
    </hibernate-mapping>

    第二种在 hibernate.cfg.xml 文件中配置:

    <!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">123456</property> 
            <property name="hibernate.hbm2ddl.auto">update</property>
            <property name="hibernate.show_sql">true</property>
            <!-- 二级缓存配置   -->
            <!-- 开启二级缓存(默认是开启二级缓存的) -->
            <property name="hibernate.cache.use_second_level_cache">true</property>
            <!-- 配置二级缓存的视实现类(第三方插件包)  以下这个缓存类的包路径是错误的
            <property name="hibernate.cache.region.factory_class">org.hibernate.cache.internal.EhCacheRegionFactory</property> -->
            <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
            <mapping resource="learnhibernateeanPerson.hbm.xml"/>
            <!-- 
                持久化类的二级缓存配置:
                1、在持久化类配置文件中配置  <cache usage="read-write"/>
                2、在 hibernate.cfg.xml 文件中配置,如下:(推荐)
             -->
            <class-cache usage="read-write" class="learn.hibernate.bean.Person"/>
        </session-factory>
    </hibernate-configuration>

    5、代码测试

    /**
     * 在配置二级缓存的查询中步骤如下:
     * 先搜索   一级缓存------> 二级缓存  ------> SQL查询-------> 将数据写入缓存中
     * 二级缓存是可以在多个 session 中共享的
     * get()、load() 方法支持二级缓存的  读写  操作
     */
    @Test
    public void testQuery(){
        session = factory.openSession();
        Person p = (Person)session.get(Person.class, 1);
        System.out.println(p);
        session.close();
        System.out.println("-------------------");
        session = factory.openSession();
        Person p2 = (Person)session.get(Person.class, 1);
        System.out.println(p2);
        session.close();
    }
    
    /**
     * list() 方法支持二级缓存的写,不支持读
     */
    @Test
    public void testQuery2(){
        String hql = "from Person";
        
        session = factory.openSession();
        Query query = session.createQuery(hql);
        List<Person> list = query.list();
        for(Person p : list){
            System.out.println(p);
        }
        session.close();
        
        System.out.println("---------------------------");
        session = factory.openSession();
        Query query2 = session.createQuery(hql);
        List<Person> list2 = query2.list();
        for(Person p : list2){
            System.out.println(p);
        }
        session.close();
        
        System.out.println("---------------------------");
        session = factory.openSession();
        Person p = (Person)session.get(Person.class, 6);
        System.out.println(p);
        session.close();
    }
    
    /**
     * iterate() 方法支持二级缓存的写读操作
     */
    @Test
    public void testQuery3(){
        String hql = "from Person";
        
        session = factory.openSession();
        Query query = session.createQuery(hql);
        Iterator<Person> it = query.iterate();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        session.close();
        
        System.out.println("---------------------------");
        session = factory.openSession();
        Query query2 = session.createQuery(hql);
        Iterator<Person> it2 = query2.iterate();
        while(it2.hasNext()){
            System.out.println(it2.next());
        }
        session.close();
        
        System.out.println("---------------------------");
        session = factory.openSession();
        Person p = (Person)session.get(Person.class, 6);
        System.out.println(p);
        session.close();
    }

    6、二级缓存的管理

    /**
     * 二级缓存的管理
     * 
     */
    @Test
    public void testQuery() throws InterruptedException{
        String hql = "from Person";
        
        session = factory.openSession();
        // 获得二级缓存的操作句柄(对象)
        Cache cache = factory.getCache();
        Query query = session.createQuery(hql);
        Iterator<Person> it = query.iterate();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("--------------------------");
        // 判断缓存中是否存在该条数据
        boolean flag = cache.containsEntity(Person.class, 7);
        System.out.println(flag);
        // 将持久化类从缓存中剔除
        cache.evictEntity(Person.class, 7);
        // 将一个持久化类型从缓存中全部剔除
        cache.evictEntityRegion(Person.class);
        session.close();
        
    }

    7、验证超出规定数量的持久化对象会不会被写入到指定的目录下

    package learn.hibernate.test;
    
    import static org.junit.Assert.*;
    
    import java.util.Iterator;
    import java.util.List;
    
    import learn.hibernate.bean.Person;
    
    import org.hibernate.Query;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class TestHibernate2 {
    
        SessionFactory factory = null;
        Session session = null;
        Transaction tx = null;
        
        /**
         * 测试之前初始化数据
         * @throws Exception
         */
        @SuppressWarnings("deprecation")
        @Before
        public void setUp() throws Exception {
            System.out.println("---------初始化数据----------");
            
            Configuration config = new Configuration().configure();
            ServiceRegistry sr = new ServiceRegistryBuilder()
            .applySettings(config.getProperties()).buildServiceRegistry();
            factory = config.buildSessionFactory(sr);
            //session = factory.openSession();
        }
    
        /**
         * 测试之后释放(销毁)数据
         * @throws Exception
         */
        @After
        public void tearDown() throws Exception {
            System.out.println("---------释放数据----------");
            /*if(session.isOpen()){
                session.close();
            }*/
        }
        
        /**
         * 测试缓存中的对象数量大于配置文件后,是否会将多余的对象写入到在磁盘上生成文件
         * 关闭  factory 是否会将磁盘文件释放删除
         * @throws InterruptedException 
         */
        @Test
        public void testQuery() throws InterruptedException{
            String hql = "from Person";
            
            session = factory.openSession();
            Query query = session.createQuery(hql);
            Iterator<Person> it = query.iterate();
            while(it.hasNext()){
                System.out.println(it.next());
            }
            session.close();
            System.out.println("--------sleep-start------");
            // 为了观察二级缓存序列化操作过程,让程序暂停短暂时间,观察磁盘文件是否生成
            Thread.sleep(10000);
            System.out.println("--------sleep-end------");
            factory.close();
        }
    }

    8、查询缓存

    首先要做 hibernate.cfg.xml 文件中配置如下代码:

    <property name="hibernate.cache.use_query_cache">true</property>

    开启查询缓存,默认情况下查询缓存是关闭的;查询缓存是基于二级缓存的

    测试:

    /**
     * 只有 list() 支持查询缓存,其他的方法不支持
     * 查询缓存的生命周期是很短暂的,即便查询条件的值发生变化也会重新查询
     * 
     */
    @Test
    public void testQuery2(){
        String hql = "from Person";
        
        session = factory.openSession();
        Query query = session.createQuery(hql);
        /**
         * 启动查询缓存
         * 告诉 hibernate 先到查询缓存中搜索有没有相同的查询语句查询过,有就将之前的查询结果直接返回
         */
        query.setCacheable(true);
        List<Person> list = query.list();
        for(Person p : list){
            System.out.println(p);
        }
        session.close();
        
        System.out.println("---------------------------");
        session = factory.openSession();
        Query query2 = session.createQuery(hql);
        // 如果查询没有变,那么接下来的查询结果将从上一次的查询中获取
        query2.setCacheable(true);
        query2.setCacheable(true);
        List<Person> list2 = query2.list();
        for(Person p : list2){
            System.out.println(p);
        }
        session.close();
    }

    9、hibernate 的优化

    (1)、使用 Configuration 装载映射文件时,不要使用绝对路径装载。最好的方式是通过 getResourceAsStream() 装载映射文件,这样 hibernate 会从 classpath 中寻找已配置的映射文件。

    (2)、SessionFactory 的创建非常消耗资源,整个应用一般只要一个 SessionFactory 就够了,只有多个数据库的时候才会使用多个 SessionFactory。

    (3)、在整个应用中,Session 和事务应该能够统一管理。(Spring 为 Hibernate 提供了很好的支持)

    (4)、将所有的集合属性配置设为懒加载(lazy=true)

    (5)、在定义关联关系时,集合首选 Set,如果集合中的实体存在重复,则选择 List(定义配置文件时,可以将 List定义为 idbag),数组的性能最差。

    (6)、在一对多的双向关联中,一般将集合的 inverse 属性设置为 true,让集合的对方维护关联关系。例如:Person-Address,由 Address 来维护 Person 和 Address 的关联关系。

    让拥有外键的一端来进行关联关系的维护比较好

    (7)、在执行更新的时候尽量配置 dynamic-update=”true”,表示没有修改的属性不参与更新操作

    (8)、HQL 子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分

    (9)、如果可以,使用乐观锁代替悲观锁

    (10)、如果要很好的掌握 Hibernate,熟练掌握关系数据理论和 SQL 是前提条件

  • 相关阅读:
    深度学习中的基本概念——梯度相关
    模型训练中涉及到的技巧
    ubuntu swapfile
    ubuntu install opencv
    Jetson TX1 安装ROS操作系统
    Redis介绍以及安装(Linux)
    C# url信息获取
    贝茨视觉训练法
    PHP设计模式浅析
    MySQL相关知识
  • 原文地址:https://www.cnblogs.com/hwlsniper/p/4297073.html
Copyright © 2011-2022 走看看