11.11 Mybatis缓存(一级缓存和二级缓存)

11.11 Mybatis缓存(一级缓存和二级缓存)

缓存的特点

特点:

  • 将数据保存再内存中

常用的缓存服务器:

  • MongoDB

  • Redis

关键点:

Mybatis提供了一级缓存和二级缓存的支持,默认情况下只开启一级缓存

一级缓存

特点:

  • 基于PerpetualCache(Mybatis自带的)的HashMap本地缓存

  • session flush或者close之后该session中的所有cache就会被清空

Mybatis的缓存机制

机制说明:

  • 参数和SQL完全一样的情况下使用同一个SqlSession对象调用同一个mapper的方法只执行一次SQL

  • Session第一次查询以后Mybatiss会将其放在缓存当中。再次查询如果没有刷新并且缓存没有超时的情况下直接取缓存的数据而不会查询数据库

关键点:

由于Sqlsession相互隔离,如果使用不同的Sqlsession对象调用相同的mapper、参数、方法时

Mybatis还是会再次发送SQL到数据库执行。

示例

WebsiteMapper接口:

package com.junkingboy.mapper;

import com.junkingboy.bean.Student;
import com.junkingboy.bean.User;
import com.junkingboy.bean.Website;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.type.JdbcType;

import java.util.List;
import java.util.Map;

/**
* @description:mybatis框架测试接口,该接口定义了.xml文件操作的表用到的方法
* @data: 2021/11/2 16:35
* @author: Lucifer
*/
public interface WebsiteMapper {
   /* 使用mybatis中自带的一级缓存进行查询操作 */
   Website selectWebsiteById(int id);
}

websiteMapper.xml

<?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.junkingboy.mapper.WebsiteMapper">
   <!-- 与selectWebsiteById的映射SQL -->
   <select id="selectWebsiteById" resultType="com.junkingboy.bean.Website">
      SELECT *
      FROM javawebtest.website
       <trim prefix="where" prefixOverrides="and">
           <if test="id != null and id != ''">
              AND id = #{id}
           </if>
       </trim>
   </select>
</mapper>

测试方法:

package com.junkingboy.test;

import com.junkingboy.bean.Website;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;

/**
* @description:测试一级缓存的查询方法
* @data: 2021/11/11 18:45
* @author: Lucifer
*/
public class Test {

   public static Logger logger = Logger.getLogger(Test.class);
   public static void main(String[] args) throws IOException {
       /* 根据配置文件构建 */
       InputStream config = Resources.getResourceAsStream("mybatis-config.xml");
       SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config);
       SqlSession ss = ssf.openSession();

       /* 通过Sqlsession接口对象执行sql语句 */
       Website site = ss.selectOne("com.junkingboy.mapper.WebsiteMapper.selectWebsiteById", 1);
       logger.debug("使用同一个Sqlsession再执行一次");
       Website website = ss.selectOne("com.junkingboy.mapper.WebsiteMapper.selectWebsiteById", 1);

       /* 使用二级缓存的时候Sqlsession调用了commit提交方法才会生效 */
       ss.commit(); //--->提交Sqlsession

       logger.debug("创建一个新的sqlsession对象再执行一次");
       SqlSession ss2 = ssf.openSession();
       Website site2 = ss2.selectOne("com.junkingboy.mapper.WebsiteMapper.selectWebsiteById", 1);
       ss2.commit();
  }
}

结果分析:

  • 第一个SqlSession实际只发生过一次查询,而第二次查询就从缓存中取出了,也就是SqlSession层面的一级缓存。

  • 这个时候需要设置二级缓存。使得缓存在SqlSessionFactory层面上能够提供给各个SqlSession对象共享。

二级缓存

二级缓存的特点:

  • 全局缓存,作用域超出 session 范围之外,可以被所有 SqlSession 共享。

二级缓存的配置:

  • 现在mybatis-config.xml中设置

  • 再在mapper当中设置

  • 对个别查询进行调整。单独设置cache

mybatis-config.xml

全局缓存配置:

<settings>
<setting name="cacheEnable" value="true" />
</settings>
<?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="logImpl" value="LOG4J"/>
       <setting name="cacheEnable" value="true"/>
   </settings>

   <!--配置mybatis的运行环境-->
   <environments default="test">
       <environment id="test">
           <!--使用JDBC的事务管理-->
           <transactionManager type="JDBC" />
           <dataSource type="POOLED">
               <!--配置mysql数据库的驱动-->
               <!--配置驱动-->
               <property name="driver" value="com.mysql.jdbc.Driver" />
               <!--连接url-->
               <property name="url" value="jdbc:mysql://localhost:3306/javawebtest?characterEncoding=utf-8"/>
               <!--配置用户名和密码-->
               <property name="username" value="root"/>
               <property name="password" value="root"/>
           </dataSource>
       </environment>
   </environments>

   <!--将mapper文件加入到配置文件中-->
   <mappers>
       <mapper resource="src/main/java/com/junkingboy/mapper/WebsiteMapper.xml" />
   </mappers>
</configuration>

mapper配置:

二级缓存的作用域是针对 mappernamescape 而言,即只有再次在 namescape 内(com.junkingboy.mapper.WebsiteMapper)的查询才能共享这个缓存

<mapper namespace="com.junkingboy.WebsiteMapper">
<!-- cache配置 -->
   <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
</mapper>

属性说明:

属性说明
eviction 代表的是缓存回收策略,目前 MyBatis 提供以下策略。LRU:使用较少,移除最长时间不用的对象;FIFO:先进先出,按对象进入缓存的顺序来移除它们;SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象;WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval 刷新间隔时间,单位为毫秒,这里配置的是 100 秒刷新,如果省略该配置,那么只有当 SQL 被执行的时候才会刷新缓存。
size 引用数目,正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。这里配置的是 1024 个对象。
readOnly 只读,默认值为 false,意味着缓存数据只能读取而不能修改,这样设置的好处是可以快速读取缓存,缺点是没有办法修改缓存。

针对个别查询修改缓存:

<select id="getWebsiteList" resultType="net.biancheng.po.Website" usecache="true">
  ...
</select>

小结

  • Mybatis专心做的应该是 SQL 映射。

  • 对于缓存,采用 OSCache、Memcached 等专门的缓存服务器来做更为合理。

It's a lonely road!!!
原文地址:https://www.cnblogs.com/JunkingBoy/p/15543477.html