Skip to content

Mybatis 缓存机制

TIP

MyBatis 内置了二级缓存机制,可以有效减少数据库查询次数,提升系统性能。

一级缓存(SqlSession 级别)

默认开启,同一个 SqlSession 中共享缓存:

java
// 同一个 SqlSession 中查询两次
try (SqlSession session = factory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);

    User user1 = mapper.selectById(1L); // 查数据库
    User user2 = mapper.selectById(1L); // 走缓存,不查数据库

    System.out.println(user1 == user2); // true(同一个对象)
}

一级缓存失效场景

java
// 1. 执行了 DML 操作(插入、更新、删除)
mapper.selectById(1L);     // 查数据库
mapper.updateById(user);   // DML 操作,清空缓存
mapper.selectById(1L);     // 重新查数据库

// 2. 调用了 clearCache()
session.clearCache();

// 3. 不同 SqlSession

二级缓存(Mapper 级别)

跨 SqlSession 共享,需手动开启:

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

<!-- Mapper XML 中开启 -->
<mapper namespace="com.example.mapper.UserMapper">
    <cache
        eviction="LRU"
        flushInterval="60000"
        size="512"
        readOnly="false"/>
</mapper>

缓存属性

属性说明默认值
eviction淘汰策略(LRU/FIFO/SOFT/WEAK)LRU
flushInterval刷新间隔(毫秒)不刷新
size缓存对象数量1024
readOnly是否只读false

使用要求

java
// 实体类必须实现 Serializable
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    // ...
}

自定义缓存

java
// 实现 Cache 接口,可以集成 Redis
public class RedisCache implements Cache {
    private String id;
    private RedisTemplate redisTemplate;

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

    @Override
    public void putObject(Object key, Object value) {
        redisTemplate.opsForValue().set(key, value, 60, TimeUnit.MINUTES);
    }

    @Override
    public Object getObject(Object key) {
        return redisTemplate.opsForValue().get(key);
    }

    @Override
    public Object removeObject(Object key) {
        return redisTemplate.delete(key);
    }

    @Override
    public void clear() {
        // 清空缓存
    }

    @Override
    public int getSize() {
        return 0;
    }
}

// 在 Mapper XML 中使用
// <cache type="com.example.cache.RedisCache"/>

TIP

  • 一级缓存默认开启且无法关闭
  • 二级缓存适用于读多写少的场景
  • 需要序列化的实体类注意修改后及时清理缓存