关于mybatis:Mybatis-的一级二级缓存

42次阅读

共计 7809 个字符,预计需要花费 20 分钟才能阅读完成。

一级缓存

Mybatis 对缓存提供反对,然而在没有配置的默认状况下,它只开启一级缓存,一级缓存只是绝对于同一个 SqlSession 而言。所以在参数和 SQL 齐全一样的状况下,咱们应用同一个 SqlSession 对象调用一个 Mapper 办法,往往只执行一次 SQL,因为应用 SelSession 第一次查问后,MyBatis 会将其放在缓存中,当前再查问的时候,如果没有申明须要刷新,并且缓存没有超时的状况下,SqlSession 都会取出以后缓存的数据,而不会再次发送 SQL 到数据库。

为什么要应用一级缓存,不必多说也晓得个大略。然而还有几个问题咱们要留神一下。

1、一级缓存的生命周期有多长?

a、MyBatis 在开启一个数据库会话时,会 创立一个新的 SqlSession 对象,SqlSession 对象中会有一个新的 Executor 对象。Executor 对象中持有一个新的 PerpetualCache 对象;当会话完结时,SqlSession 对象及其外部的 Executor 对象还有 PerpetualCache 对象也一并开释掉。

b、如果 SqlSession 调用了 close()办法,会开释掉一级缓存 PerpetualCache 对象,一级缓存将不可用。

c、如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,然而该对象仍可应用。

d、SqlSession 中执行了任何一个 update 操作(update()、delete()、insert()),都会清空 PerpetualCache 对象的数据,然而该对象能够持续应用

   2、怎么判断某两次查问是完全相同的查问?

mybatis 认为,对于两次查问,如果以下条件都齐全一样,那么就认为它们是完全相同的两次查问。

2.1 传入的 statementId

2.2 查问时要求的后果集中的后果范畴

2.3. 这次查问所产生的最终要传递给 JDBC java.sql.Preparedstatement 的 Sql 语句字符串(boundSql.getSql())

2.4 传递给 java.sql.Statement 要设置的参数值

二级缓存:

MyBatis 的二级缓存是 Application 级别的缓存,它能够进步对数据库查问的效率,以进步利用的性能。

MyBatis 的缓存机制整体设计以及二级缓存的工作模式

SqlSessionFactory 层面上的二级缓存默认是不开启的,二级缓存的开启须要进行配置,实现二级缓存的时候,MyBatis 要求返回的 POJO 必须是可序列化的。也就是要求实现 Serializable 接口,配置办法很简略,只须要在映射 XML 文件配置就能够开启缓存了 <cache/>,如果咱们配置了二级缓存就意味着:

  • 映射语句文件中的所有 select 语句将会被缓存。
  • 映射语句文件中的所欲 insert、update 和 delete 语句会刷新缓存。
  • 缓存会应用默认的 Least Recently Used(LRU,最近起码应用的)算法来发出。
  • 依据时间表,比方 No Flush Interval,(CNFI 没有刷新距离),缓存不会以任何工夫程序来刷新。
  • 缓存会存储列表汇合或对象 (无论查询方法返回什么) 的 1024 个援用
  • 缓存会被视为是 read/write(可读 / 可写)的缓存,意味着对象检索不是共享的,而且能够平安的被调用者批改,不烦扰其余调用者或线程所做的潜在批改。

实际:

一、创立一个 POJO Bean 并序列化

因为二级缓存的数据不肯定都是存储到内存中,它的存储介质多种多样,所以须要给缓存的对象执行序列化。(如果存储在内存中的话,实测不序列化也能够的。)

package com.yihaomen.mybatis.model;

import com.yihaomen.mybatis.enums.Gender;
import java.io.Serializable;
import java.util.List;

/**
 *  @ProjectName: springmvc-mybatis 
 */
public class Student implements Serializable{

    private static final long serialVersionUID = 735655488285535299L;
    private String id;
    private String name;
    private int age;
    private Gender gender;
    private List<Teacher> teachers;
    setters&getters()....;
    toString();}

 二、在映射文件中开启二级缓存

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper">
    <!-- 开启本 mapper 的 namespace 下的二级缓存 -->
    <!--
        eviction: 代表的是缓存回收策略,目前 MyBatis 提供以下策略。(1) LRU, 最近起码应用的,一处最长工夫不必的对象
        (2) FIFO, 先进先出,按对象进入缓存的程序来移除他们
        (3) SOFT, 软援用,移除基于垃圾回收器状态和软援用规定的对象
        (4) WEAK, 弱援用,更踊跃的移除基于垃圾收集器状态和弱援用规定的对象。这里采纳的是 LRU,移除最长工夫不必的对形象

        flushInterval: 刷新间隔时间,单位为毫秒,这里配置的是 100 秒刷新,如果你不配置它,那么当
        SQL 被执行的时候才会去刷新缓存。size: 援用数目,一个正整数,代表缓存最多能够存储多少个对象,不宜设置过大。设置过大会导致内存溢出。这里配置的是 1024 个对象

        readOnly: 只读,意味着缓存数据只能读取而不能批改,这样设置的益处是咱们能够疾速读取缓存,毛病是咱们没有
        方法批改缓存,他的默认值是 false,不容许咱们批改
    -->
    <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
    <resultMap id="studentMap" type="Student">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
    </resultMap>
    <resultMap id="collectionMap" type="Student" extends="studentMap">
        <collection property="teachers" ofType="Teacher">
            <id property="id" column="teach_id" />
            <result property="name" column="tname"/>
            <result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
            <result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
            <result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/>
        </collection>
    </resultMap>
    <select id="selectStudents" resultMap="collectionMap">
        SELECT
            s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree
        FROM
            student s
        LEFT JOIN
            stu_teach_rel str
        ON
            s.id = str.stu_id
        LEFT JOIN
            teacher t
        ON
            t.id = str.teach_id
    </select>
    <!-- 能够通过设置 useCache 来规定这个 sql 是否开启缓存,ture 是开启,false 是敞开 -->
    <select id="selectAllStudents" resultMap="studentMap" useCache="true">
        SELECT id, name, age FROM student
    </select>
    <!-- 刷新二级缓存
    <select id="selectAllStudents" resultMap="studentMap" flushCache="true">
        SELECT id, name, age FROM student
    </select>
    -->
</mapper>

三、在 mybatis-config.xml 中开启二级缓存

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 这个配置使全局的映射器 (二级缓存) 启用或禁用缓存 -->
        <setting name="cacheEnabled" value="true" />
        .....
    </settings>
    ....
</configuration>

四、测试

package com.yihaomen.service.student;

import com.yihaomen.mybatis.dao.StudentMapper;
import com.yihaomen.mybatis.model.Student;
import com.yihaomen.mybatis.model.Teacher;
import com.yihaomen.service.BaseTest;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;

/**
 *   
 *  @ProjectName: springmvc-mybatis 
 */
public class TestStudent extends BaseTest {public static void selectAllStudent() {SqlSessionFactory sqlSessionFactory = getSession();
        SqlSession session = sqlSessionFactory.openSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        List<Student> list = mapper.selectAllStudents();
        System.out.println(list);
        System.out.println("第二次执行");
        List<Student> list2 = mapper.selectAllStudents();
        System.out.println(list2);
        session.commit();
        System.out.println("二级缓存观测点");
        SqlSession session2 = sqlSessionFactory.openSession();
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        List<Student> list3 = mapper2.selectAllStudents();
        System.out.println(list3);
        System.out.println("第二次执行");
        List<Student> list4 = mapper2.selectAllStudents();
        System.out.println(list4);
        session2.commit();}

    public static void main(String[] args) {selectAllStudent();
    }
}

后果:

[QC] DEBUG [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(98) | Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@51e0173d]
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Preparing: SELECT id, name, age FROM student
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Parameters:
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | <== Total: 6
[Student{id=’1′, name=’ 刘德华 ’, age=55, gender=null, teachers=null}, Student{id=’2′, name=’ 张惠妹 ’, age=49, gender=null, teachers=null}, Student{id=’3′, name=’ 谢霆锋 ’, age=35, gender=null, teachers=null}, Student{id=’4′, name=’ 王菲 ’, age=47, gender=null, teachers=null}, Student{id=’5′, name=’ 汪峰 ’, age=48, gender=null, teachers=null}, Student{id=’6′, name=’ 章子怡 ’, age=36, gender=null, teachers=null}]
第二次执行
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.0
[Student{id=’1′, name=’ 刘德华 ’, age=55, gender=null, teachers=null}, Student{id=’2′, name=’ 张惠妹 ’, age=49, gender=null, teachers=null}, Student{id=’3′, name=’ 谢霆锋 ’, age=35, gender=null, teachers=null}, Student{id=’4′, name=’ 王菲 ’, age=47, gender=null, teachers=null}, Student{id=’5′, name=’ 汪峰 ’, age=48, gender=null, teachers=null}, Student{id=’6′, name=’ 章子怡 ’, age=36, gender=null, teachers=null}]
二级缓存观测点
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.3333333333333333
[Student{id=’1′, name=’ 刘德华 ’, age=55, gender=null, teachers=null}, Student{id=’2′, name=’ 张惠妹 ’, age=49, gender=null, teachers=null}, Student{id=’3′, name=’ 谢霆锋 ’, age=35, gender=null, teachers=null}, Student{id=’4′, name=’ 王菲 ’, age=47, gender=null, teachers=null}, Student{id=’5′, name=’ 汪峰 ’, age=48, gender=null, teachers=null}, Student{id=’6′, name=’ 章子怡 ’, age=36, gender=null, teachers=null}]
第二次执行
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.5
[Student{id=’1′, name=’ 刘德华 ’, age=55, gender=null, teachers=null}, Student{id=’2′, name=’ 张惠妹 ’, age=49, gender=null, teachers=null}, Student{id=’3′, name=’ 谢霆锋 ’, age=35, gender=null, teachers=null}, Student{id=’4′, name=’ 王菲 ’, age=47, gender=null, teachers=null}, Student{id=’5′, name=’ 汪峰 ’, age=48, gender=null, teachers=null}, Student{id=’6′, name=’ 章子怡 ’, age=36, gender=null, teachers=null}]

Process finished with exit code 0

咱们能够从后果看到,sql 只执行了一次,证实咱们的二级缓存失效了。

https://gitee.com/huayicompany/springmvc-mybatis

正文完
 0