9、MyBatis-Cache

一、一级缓存

/**
 * 一级缓存(本地缓存):SqlSession 级别。一级缓存是默认开启的,为 SqlSession 级别的一个Map
 * 与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中获取。
 */
public static void main(String[] args) throws IOException {
    SqlSession session = null;
    try {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession();

        MyUserMapper mapper = session.getMapper(MyUserMapper.class);
        System.out.println(mapper.selectMyUserById(7));
        System.out.println(mapper.selectMyUserById(7));
    } finally {
        session.close();
    }
}

一级缓存失效的几种情况,相同的查询也会向数据库发送SQL

public static void main(String[] args) throws IOException {
    SqlSession session = null;
    try {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession();
        MyUserMapper mapper = session.getMapper(MyUserMapper.class);

        // sqlSession 不同
        System.out.println(mapper.selectMyUserById(7));
        session = sqlSessionFactory.openSession();
        mapper = session.getMapper(MyUserMapper.class);
        System.out.println(mapper.selectMyUserById(7));

        // sqlSession 相同,查询条件不同(当前一级缓存中还没有这个数据)
        System.out.println(mapper.selectMyUserById(7));
        System.out.println(mapper.selectMyUserById(8));

        // sqlSession 相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
        System.out.println(mapper.selectMyUserById(7));
        mapper.updateMyUser(new MyUser(10,"xasx",24,null));
        System.out.println(mapper.selectMyUserById(7));

        // sqlSession 相同,手动清除了一级缓存
        System.out.println(mapper.selectMyUserById(7));
        session.clearCache();
        System.out.println(mapper.selectMyUserById(7));
    } finally {
        session.close();
    }
}

 

二、二级缓存

1.开启二级缓存 mybatis-config.xml

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

    <!-- 自动映射有三种模式,NONE、PARTIAL、FULL。NONE 不启用自动映射,PARTIAL 只对非嵌套的 resultMap 进行自动映射,FULL 表示对所有的 resultMap 都进行自动映射。默认为 PARTIAL -->
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <!-- 数据库字段下划线转Bean字段的驼峰命名 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!-- 控制台打印SQL -->
    <setting name="logImpl" value="STDOUT_LOGGING" />

    <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认false -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。默认false (true in ≤3.4.1) -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

2.配置二级缓存 xxxMapper.xml

<!-- namespace 对应接口文件的全路径 -->
<mapper namespace="com.dao.MyUserMapper">
    <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache>
    <!-- eviction:缓存的回收策略:默认的是 LRU
            • LRU – 最近最少使用的:移除最长时间不被使用的对象。
            • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
            • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
            • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
        flushInterval:缓存刷新间隔,缓存多长时间清空一次,默认不清空,设置一个毫秒值
        readOnly:缓存中的数据是否只读
            true:只读,会将数据在缓存中的引用交给用户。数据可能被修改,不安全,速度快
            false:非只读,会利用序列化和反序列的技术克隆一份新的数据返回。安全,速度慢
        size:缓存存放多少元素
        type:指定自定义缓存的全类名,实现 org.apache.ibatis.cache.Cache 接口 -->
    <select id="selectMyUserById" resultType="myUser">
      select * from myuser where id = #{id}
    </select>

3.实体类实现序列化接口 Serializable

public class MyUser implements Serializable {
    private Integer id;
    private String name;
    private Integer age;
    private Dept dept;

4.测试

/**
 * 二级缓存(全局缓存):基于 namespace 级别的缓存,一个 namespace 对应一个二级缓存(map)
 * 
 * 创建会话:查询一条数据,这个数据就会被放在当前会话的一级缓存中
 * 会话关闭:一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,会先找二级缓存中的内容,没有就在找一级缓存,再没有就会发送 SQL 查询数据库
 * 效果:数据会从二级缓存中获取,查出的数据都会被默认先放在一级缓存中。只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
 * 使用:
 *  1)、在全局配置中开启二级缓存:<setting name="cacheEnabled" value="true"/>
 *     2)、在 xxxMapper.xml 中配置二级缓存:<cache/>
 *     3)、POJO 实现序列化接口 Serializable
 */
public static void main(String[] args) throws IOException {
    SqlSession session = null;
    try {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession();
        
        MyUserMapper mapper = session.getMapper(MyUserMapper.class);
        System.out.println(mapper.selectMyUserById(7));

        // 关闭 session 让一级缓存中类容提交到二级缓存
        session.close();

        // 重新获取 sqlSession
        session = sqlSessionFactory.openSession();
        mapper = session.getMapper(MyUserMapper.class);
        System.out.println(mapper.selectMyUserById(7));
    } finally {
        session.close();
    }
}

 

三、缓存相关配置

代码配置

// 只清除当前 session 的一级缓存
session.clearCache();

全局设置

<settings>
    <!-- 二级缓存设置,不影响一级缓存 -->
    <setting name="cacheEnabled" value="false"/>
    <!-- 本地(一级)缓存作用域,默认 SESSION,会缓存一个会话(SqlSession)中执行的所有查询。 设置为 STATEMENT,会话仅作用在语句执行上,对 SqlSession 的调用将不会共享数据,可认为是禁用一级缓存 -->
    <setting name="localCacheScope" value="SESSION"/>
</settings>

SQL 映射文件配置

<!-- flushCache:将其设置为 true,任何时候只要 SQL 被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句),false(对应查询语句)。
     useCache:将其设置为 true,将会导致本条 SQL 的结果被二级缓存(不影响一级),默认值:对 select 元素为 true -->
<select id="selectMyUserById" resultType="myUser" useCache="true" flushCache="false">
  select * from myuser where id = #{id}
</select>

也可以在接口上配置

@Options(flushCache = Options.FlushCachePolicy.FALSE, useCache = true)
public MyUser selectMyUserById(Integer id);

 

四,使用第三方缓存

以 ehcache 为例子

1.导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>3.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.26</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- 指定jdk -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.添加缓存配置文件 ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!-- 磁盘保存路径 -->
    <diskStore path="D:\ehcache" />

    <!--
        diskStore:指定数据在磁盘中的存储位置。
        defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略

        以下是必须属性:
        maxElementsInMemory - 在内存中缓存的element的最大数目
        maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
        eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
        overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上

        以下是可选属性:
        timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
        timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
        diskSpoolBufferSizeMB - 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
        diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
        diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
        memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
    -->
    <defaultCache
            maxElementsInMemory="10000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

3.修改缓存配置,xxxMapper.xml

<!-- namespace 对应接口文件的全路径 -->
<mapper namespace="com.dao.MyUserMapper">
    <!-- 引用缓存:namespace:指定和哪个名称空间下的缓存一样 -->
    <!--<cache-ref namespace="com.dao.Dept"/>-->
    
    <!--使用自定义缓存-->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    <select id="selectMyUserById" resultType="myUser" useCache="true" flushCache="false">
      select * from myuser where id = #{id}
    </select>

5.测试

/**
 * 使用第三方缓存:
 *    1)、导入依赖;
 *    2)、xxxMapper.xml 中使用自定义缓存 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
 */
public static void main(String[] args) throws IOException {
    SqlSession session = null;
    try {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        
        session = sqlSessionFactory.openSession();
        MyUserMapper mapper = session.getMapper(MyUserMapper.class);
        System.out.println(mapper.selectMyUserById(7));
        
        session.close();

        session = sqlSessionFactory.openSession();
        mapper = session.getMapper(MyUserMapper.class);
        System.out.println(mapper.selectMyUserById(7));
    } finally {
        if (session != null) {
            session.close();
        }
    }
}


http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

http://www.mybatis.org/ehcache-cache/index.html

猜你喜欢

转载自www.cnblogs.com/jhxxb/p/10495953.html