Mybatis缓存简单理解

一级缓存

1.首先明确什么是sqlSession

sqlSession是Mybatis的关键对象,是执行持久化操作的独享,有点类似于JDBC中的Connection对象,它是应用程序与持久层交互的一个单线程对象,它包括了以数据库为背景的所有执行SQL的操作方法,它的底层封装了JDBC连接,可以用sqlSession实例直接执行被映射的sql语句,每个线程都应该有自己的sqlSession实例,sqlSession实例不能被共享,同时也是线程不安全的,在使用完成之后我们要确保在finally代码块中关闭它。

//SqlSession接口源码如下所示:

package org.apache.ibatis.session;

import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.executor.BatchResult;

public interface SqlSession extends Closeable {

  <T> T selectOne(String statement);

  <T> T selectOne(String statement, Object parameter);

  <E> List<E> selectList(String statement);

  <E> List<E> selectList(String statement, Object parameter);

  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

  <K, V> Map<K, V> selectMap(String statement, String mapKey);

  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);

  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

  void select(String statement, Object parameter, ResultHandler handler);

  void select(String statement, ResultHandler handler);

  void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

  int insert(String statement);

  int insert(String statement, Object parameter);

  int update(String statement);

  int update(String statement, Object parameter);

  int delete(String statement);

  int delete(String statement, Object parameter);

  void commit();

  void commit(boolean force);

  void rollback();

  void rollback(boolean force);

  List<BatchResult> flushStatements();

  void close();

  void clearCache();

  Configuration getConfiguration();

  <T> T getMapper(Class<T> type);

  Connection getConnection();
}

2.说明

  1. 在同一个sqlSession中,mybatis会把执行的方法名称跟参数按照一定规则拼接成Map的key值,将缓存的结果放入Map的value中,如果后续的key一样则直接读取value。
  2. 不同的sqlSession中缓存是隔离的
  3. 使用INSERT,DELETE,UPDATE都会清空缓存
  4. 使用配置可以清空同一个sqlSession中的缓存
<select id="selectByPrimaryKey" flushCache="true" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from student
    where student_id=#{id, jdbcType=INTEGER}
</select>

二级缓存

1.开启二级缓存后流程图

如果要实现多个sqlSession共享缓存,则需要开启二级缓存 (使用同一个namespace),sqlSession对象会使用CachingExecutor装饰 Executor 查询相应namespace下的缓存数据,如果没有的话将任务给Executor去查询一级缓存,最后执行查询数据库的过程。
顺序为:二级缓存 -> 一级缓存 -> 数据库
工作流程

2.二级缓存如何开启

-------------------spring + springMVC + mybatis ----------------------------
<settings>
	<setting name = "cacheEnabled" value = "true" />
</settings>
-------------------springBoot+ mybatis --------------------------------------
mybatis-plus.configuration.cache-enabled=true
--------------------- 在mapper.xml文件中使用 ----------------------------------
// 只需要使用cache标签即可 可以自定义缓存类型结合第三方缓存 比如redis
<cache type="com.example.demo.redis.cache.MybatisRedisCache"/>
<cache/>
public class MybatisRedisCache implements Cache {
    private static final Logger log = LoggerFactory.getLogger(MybatisRedisCache.class);
    private String id;
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间


    public MybatisRedisCache(String id) {
        this.id = id;
    }

    private RedisTemplate<Object, Object> getRedisTemplate(){
        return ApplicationContextHolder.getBean("redisTemplate");
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object key, Object value) {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.boundHashOps(getId()).put(key, value);
        log.info("[结果放入到缓存中: " + key + "=" + value+" ]");

    }

    @Override
    public Object getObject(Object key) {
        RedisTemplate redisTemplate = getRedisTemplate();
        Object value = redisTemplate.boundHashOps(getId()).get(key);
        log.info("[从缓存中获取了: " + key + "=" + value+" ]");
        return value;
    }

    @Override
    public Object removeObject(Object key) {
        RedisTemplate redisTemplate = getRedisTemplate();
        Object value = redisTemplate.boundHashOps(getId()).delete(key);
        log.info("[从缓存删除了: " + key + "=" + value+" ]");
        return value;
    }

    @Override
    public void clear() {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.delete(getId());
        log.info("清空缓存!!!");
    }

    @Override
    public int getSize() {
        RedisTemplate redisTemplate = getRedisTemplate();
        Long size = redisTemplate.boundHashOps(getId()).size();
        return size == null ? 0 : size.intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }
}
//需要注意的点
  • 自定义实现的二级缓存,必须要有一个带id的构造函数,否则会报错。
  • 这里不能通过@Autowire的方式引用redisTemplate,因为RedisCache并不是Spring容器里的bean。所以我们需要手动地去调用容器的getBean方法来拿到这个bean,那么这样,我们就需要引入ApplicationContextHolder这个类。

3.Mybatis cache标签

<cache/> 
  • 映射语句中所有select语句都会被缓存
  • 映射语句中所有INSERT,UPDATE,DELETE语句都会刷新缓存
  • 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回
  • 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
  • 存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
  • 缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>
  
 1. eviction:回收策略
   LRU:最近最少被使用的数据 
   FIFO:先进先出 
   SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象 
   WEAK:弱引用 更积极地移除基于垃圾收集器状态和弱引用规则的对象。
 
 2.flushInterval:定时刷新 单位为毫秒,默认情况不设置 采用语句刷新的方式
 3.size:存数结果对象或列表的 512 个引用,默认为 1024.
 4.readOnly:而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。默认为false,可读写的缓存会返回对象反序列化的拷贝,线程安全但是速度较慢。
 
 -------------------------也可以在特定的sql上利用flushCache,useCache来控制是否开启缓存--------------------
<select ... flushCache="false" useCache="true"/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值