zoukankan      html  css  js  c++  java
  • MyBatis

    MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。

    • MyBatis系统中默认定义了两级缓存。
    • 一级缓存和二级缓存。
      • 1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
      • 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
      • 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

    1.一级缓存

    • 一级缓存(local cache), 即本地缓存, 作用域默认为sqlSession。当 Session flush 或 close 后, 该Session 中的所有 Cache 将被清空。
    • 本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域.
    • 在mybatis3.1之后, 可以配置本地缓存的作用域.
      在 mybatis.xml 中配置
    设置参数 描述 有效值 默认值
    localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。
    若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
    SESSION STATEMENT

    1.1 一级缓存演示&失效情况

    • 同一次会话期间只要查询过的数据都会保存在当
      前SqlSession的一个Map中

      • key:hashCode+查询的SqlId+编写的sql查询语句+参数
    • 一级缓存失效的四种情况

      • 1、不同的SqlSession对应不同的一级缓存
      • 2、同一个SqlSession但是查询条件不同
      • 3、同一个SqlSession两次查询期间执行了任何一次增删改操作
      • 4、同一个SqlSession两次查询期间手动清空了缓存

    2.二级缓存

    • 二级缓存(second level cache),全局作用域缓存
    • 二级缓存默认不开启,需要手动配置
    • MyBatis提供二级缓存的接口以及实现,缓存实现要求 POJO实现Serializable接口
    • 二级缓存在 SqlSession 关闭或提交之后才会生效

    (1)使用步骤

    • 1、全局配置文件中开启二级缓存
      • <setting name="cacheEnabled" value="true"/>
    • 2、需要使用二级缓存的映射文件处使用cache配置缓存
      • <cache />
    • 3、注意:POJO需要实现Serializable接口

    Mapper里面的

    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    
    • eviction 可用的回收策略有:

      • LRU – 最近最少使用的:移除最长时间不被使用的对象。
      • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
      • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
      • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    • flushInterval:刷新间隔,单位毫秒 •

      • 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
    • size:引用数目,正整数

      • 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
    • readOnly:只读,true/false

      • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象 不能被修改。这提供了很重要的性能优势。
      • false(默认):读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些, 但是安全,因此默认是 false。

    (2)使用自定义缓存
    除了这些自定义缓存的方式, 你也可以通过实现你自己的缓存或为其他第三方缓存方案 创建适配器来完全覆盖缓存行为。

    <cache type="com.domain.something.MyCustomCache"/>
    

    2.1 二级缓存案例:

    参照上面的步骤:
    (1)全局配置mybatis-config.xml

    <settings>
     <!--开启二级缓存-->
      <setting name="cacheEnabled" value="true"></setting>
      ...
    

    (2)在 employeeMapper.xml 里添加 <cache>标签

    <mapper namespace="com.tangge.Mapper.employeeMapper">
      <cache></cache>
    

    (3)POJO需要实现 Serializable 接口

    com.tangge.model.employee 实现接口 Serializable

    @Alias("emp")
    public class employee implements Serializable{
    ...
    }
    

    ---->【测试】:

    /**
         * 缓存:
         * - 一级缓存:本地缓存 sqlSession 级别
         * 与数据库同一次会话期间查询到的数据会缓存到本地缓存中,以后需要获取相同数据,直接缓存中拿。
         *
         * - 二级缓存:全局缓存 nameSpace 级别
         *      工作机制:
         *          1.一条查询被放入一级缓存中。
         *          2.如果会话关闭,一级缓存数据会被保存到二级缓存中。新查询,可以参照二级缓存。
         *          3.sqlSession === EmployeeMapper  ===> Employee
         *                           DepartmentMapper===> Department
         *            不同namespace查出的数据会被放在自己对应的缓存中(map)
         *            效果:数据会从二级缓存中获取。
         *            查出的数据,默认放在一级缓存中,只有会话提交关闭以后,一级缓存中数据才会放入二级缓存。
         */
        public static void getTwoLevelCache() {
            SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
            SqlSession session = sqlSessionFactory.openSession();
            SqlSession session2 = sqlSessionFactory.openSession();
            try {
                employeeMapper mapper = session.getMapper(employeeMapper.class);
                employeeMapper mapper2 = session2.getMapper(employeeMapper.class);
                //第1次查询
                employee emp = mapper.getEmployeeById(1);
                System.out.println(emp);
                session.close();
                //第2次查询
                employee emp2 = mapper2.getEmployeeById(1);
                System.out.println(emp2);
                session2.close();
            } finally {
    
            }
        }
    

    注意个问题:

    查出的数据,默认放在一级缓存中,只有会话提交关闭以后,一级缓存中数据才会放入二级缓存。

    3.缓存有关设置

    • 1、全局setting的cacheEnable:
      • 配置二级缓存的开关。一级缓存一直是打开的。
    • 2、select标签的useCache属性:
      • 配置这个select是否使用二级缓存。一级缓存一直是使用的
    • 3、sql标签的flushCache属性:
      • 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。
        查询<select>标签:默认flushCache=false。
    • 4、sqlSession.clearCache():
      • 只是用来清除一级缓存。
    • 5、当在某一个作用域 (一级缓存Session/二级缓存
      Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

    4.第三方包

    4.1 ehcache

    http://www.java2s.com/example/jar/e/ehcache-core-index.html
    ehcache-core-2.6.6.jar(降级测试)
    slf4j.api-1.6.1.jar
    slf4j-log4j12-1.7.1.jar

    https://github.com/mybatis/ehcache-cache/releases
    mybatis-ehcache-1.0.3
    帮助文档:http://www.mybatis.org/ehcache-cache/

    4.1.1 配置说明

    diskStore : ehcache支持内存和磁盘两种存储

    path :指定磁盘存储的位置
    defaultCache : 默认的缓存

    maxEntriesLocalHeap=”10000”
    eternal=”false”
    timeToIdleSeconds=”120”
    timeToLiveSeconds=”120”
    maxEntriesLocalDisk=”10000000”
    diskExpiryThreadIntervalSeconds=”120”
    memoryStoreEvictionPolicy=”LRU”
    cache :自定的缓存,当自定的配置不满足实际情况时可以通过自定义(可以包含多个cache节点)

    name : 缓存的名称,可以通过指定名称获取指定的某个Cache对象

    maxElementsInMemory :内存中允许存储的最大的元素个数,0代表无限个

    clearOnFlush:内存数量最大时是否清除。

    eternal :设置缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。根据存储数据的不同,例如一些静态不变的数据如省市区等可以设置为永不过时

    timeToIdleSeconds : 设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。

    timeToLiveSeconds :缓存数据的生存时间(TTL),也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。

    overflowToDisk :内存不足时,是否启用磁盘缓存。

    maxEntriesLocalDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。

    maxElementsOnDisk:硬盘最大缓存个数。

    diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。

    diskPersistent:是否在VM重启时存储硬盘的缓存数据。默认值是false。

    diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。

    4.1.2 配置步骤

    1.配置文档:

    <ehcache
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
      updateCheck="false">
    
      <diskStore path="E:开发工具jar安装包缓存ehcache-disksotre"/>
      <defaultCache
        maxElementsInMemory="20000"
        maxElementsOnDisk="10000000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"
      />
      <cache name="eternalCache"
        maxElementsInMemory="20000"
        eternal="true"
        overflowToDisk="true"
        diskPersistent="false"
        timeToLiveSeconds="0"
        diskExpiryThreadIntervalSeconds="120"
      />
    </ehcache>
    

    2.在Mapper的<cache>设置

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    

    4.1.3 修改一处Mapper,改其他所有

    其他Mapper配置,引用同一个Mapper命名空间里的cache设置

    <cache-ref namespace="">
    

    好多坑

    (1)ehcache-core-2.7.1.jar
    问题:
    1.Caused by: java.lang.ClassNotFoundException: org.terracotta.statistics.StatisticsManager
    解决方案:
    The previous 2.7.0 version had these classes present.
    2.70 版本以上都有这个问题了
    Our maven setup must is :

    <dependency>
    	<groupId>net.sf.ehcache</groupId>
    	<artifactId>ehcache</artifactId>
    	<version>2.7.0</version>
    	<exclusions>
    		<exclusion>
    			<groupId>net.sf.ehcache.internal</groupId>
    			<artifactId>ehcache-terracotta-bootstrap</artifactId>
    		</exclusion>
    		<exclusion>
    			<groupId>org.terracotta.internal</groupId>
    			<artifactId>statistics</artifactId>
    		</exclusion>
    	</exclusions>
    </dependency>
    
  • 相关阅读:
    POJ 2923 Relocation ★(状态压缩+01背包)
    POJ 1062 昂贵的聘礼 (带限制的最短路)
    HDU 4355 Party All the Time (三分求凸函数极值)
    POJ 1860 Currency Exchange (BellmanFord)
    POJ 2923 Relocation ★(状态压缩+01背包)
    【HNOI2011】数学作业(BZOJ 2326)
    POJ 1062 昂贵的聘礼 (带限制的最短路)
    作为当代大学生,面对着信息增长加快,老化周期变短,你应该如何做?
    作为当代大学生,面对着信息增长加快,老化周期变短,你应该如何做?
    信息分析与预测考前模拟试题
  • 原文地址:https://www.cnblogs.com/tangge/p/9549461.html
Copyright © 2011-2022 走看看