HOME> 攻略大全> MyBatis缓存机制:一级缓存、二级缓存、PerpetualCache、namespace缓存详解

MyBatis缓存机制:一级缓存、二级缓存、PerpetualCache、namespace缓存详解

2026-08-05 00:00:16

MyBatis缓存机制详解

缓存概述​

MyBatis提供了两级缓存机制来提升查询性能,减少数据库访问次数。

一级缓存​

基本特性​

一级缓存是SqlSession级别的缓存,默认开启且无法关闭。

核心特点:

作用域:SqlSession内部

实现:PerpetualCache(基于HashMap)

生命周期:与SqlSession相同

清空时机:执行update/delete/insert或手动清空

工作流程​

使用示例​

@Testpublic void testFirstLevelCache() { SqlSession session = sqlSessionFactory.openSession(); try { ProductMapper mapper = session.getMapper(ProductMapper.class); // 第一次查询 - 访问数据库 Product product1 = mapper.findById(1001L); System.out.println("First query: " + product1); // 第二次查询 - 命中一级缓存,不访问数据库 Product product2 = mapper.findById(1001L); System.out.println("Second query: " + product2); // 两次查询返回同一个对象 assert product1 == product2; // 执行更新操作 - 清空一级缓存 Product updateProduct = new Product(); updateProduct.setId(1002L); updateProduct.setPrice(new BigDecimal("999")); mapper.updateProduct(updateProduct); // 再次查询 - 重新访问数据库 Product product3 = mapper.findById(1001L); System.out.println("Third query: " + product3); } finally { session.close(); }}

源码实现​

public class PerpetualCache implements Cache { private final String id; private final Map cache = new HashMap<>(); @Override public void putObject(Object key, Object value) { cache.put(key, value); } @Override public Object getObject(Object key) { return cache.get(key); } @Override public Object removeObject(Object key) { return cache.remove(key); } @Override public void clear() { cache.clear(); }}

缓存Key生成​

一级缓存的Key由多个因素组成:

public class CacheKey implements Cloneable, Serializable { private static final int DEFAULT_MULTIPLIER = 37; private static final int DEFAULT_HASHCODE = 17; private int multiplier; private int hashcode; private long checksum; private int count; private List updateList; public void update(Object object) { // 更新hashcode和checksum int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object); count++; checksum += baseHashCode; baseHashCode *= count; hashcode = multiplier * hashcode + baseHashCode; updateList.add(object); }}

CacheKey包含以下信息:

MappedStatement的id

RowBounds的offset和limit

SQL语句

参数值

Environment的id

一级缓存的问题​

1. 作用域限制

// 问题场景:不同SqlSession无法共享缓存SqlSession session1 = sqlSessionFactory.openSession();SqlSession session2 = sqlSessionFactory.openSession();ProductMapper mapper1 = session1.getMapper(ProductMapper.class);ProductMapper mapper2 = session2.getMapper(ProductMapper.class);// session1查询,缓存在session1中Product p1 = mapper1.findById(1001L);// session1更新数据p1.setPrice(new BigDecimal("999"));mapper1.updateProduct(p1);session1.commit();// session2查询 - 仍然返回旧数据(脏数据)Product p2 = mapper2.findById(1001L);

2. 容量无限制

// 一级缓存没有容量限制,可能导致内存溢出for (int i = 0; i < 100000; i++) { mapper.findById((long) i); // 每次查询都缓存}

配置说明​

可以通过localCacheScope设置缓存级别:

二级缓存​

基本特性​

二级缓存是namespace级别的缓存,需要手动开启。

核心特点:

作用域:namespace(Mapper)

跨SqlSession共享

需要手动配置开启

支持多种缓存实现

装饰器模式实现

开启二级缓存​

步骤1:全局配置

步骤2:Mapper配置

配置属性说明:

eviction: 缓存回收策略

LRU(默认):最近最少使用

FIFO:先进先出

SOFT:软引用

WEAK:弱引用

flushInterval: 刷新间隔(毫秒)

size: 缓存对象数量(默认1024)

readOnly: 是否只读

true:返回缓存对象的同一实例(性能好,但不安全)

false:返回缓存对象的副本(安全,但性能差)

步骤3:实体类实现Serializable

public class Product implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String name; private BigDecimal price; // ...}

工作流程​

装饰器模式实现​

MyBatis使用装饰器模式增强缓存功能:

👉 点击解锁全部付费内容

现在就开始投资吧 | 12种最佳复利资产
依纷内衣怎么样?深度评测与使用心得
Copyright © 2022 奇业网游-最新活动中心_热门游戏攻略_限时礼包领取 All Rights Reserved.