MyBatis中的一级和二级缓存怎么用

发布时间:2021-12-30 09:46:10 作者:小新
来源:亿速云 阅读:187
# MyBatis中的一级和二级缓存怎么用

## 一、MyBatis缓存机制概述

### 1.1 什么是ORM框架缓存
ORM框架缓存是指对象关系映射框架为了提高数据库访问性能,将查询结果暂时存储在内存中的机制。当应用程序再次需要相同数据时,可以直接从内存中获取,避免重复访问数据库。

### 1.2 MyBatis缓存体系结构
MyBatis提供了一套完整的缓存解决方案,分为两个层级:
- 一级缓存(Local Cache):SqlSession级别的缓存
- 二级缓存(Global Cache):Mapper级别的缓存

### 1.3 缓存的工作流程
1. 执行查询时首先检查一级缓存
2. 一级缓存未命中时检查二级缓存
3. 二级缓存未命中才访问数据库
4. 查询结果按需存入相应缓存

## 二、一级缓存详解

### 2.1 一级缓存的基本特性
- **作用范围**:默认开启,基于SqlSession
- **生命周期**:与SqlSession相同
- **存储位置**:内存中的PerpetualCache对象
- **实现原理**:HashMap结构存储查询结果

### 2.2 一级缓存的使用示例

```java
try(SqlSession sqlSession = sqlSessionFactory.openSession()) {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
    // 第一次查询,访问数据库
    User user1 = mapper.selectById(1);
    
    // 第二次查询相同数据,直接从一级缓存获取
    User user2 = mapper.selectById(1);
    
    System.out.println(user1 == user2); // 输出true,说明是同一个对象
}

2.3 一级缓存的失效场景

  1. SqlSession不同
// 两个不同的SqlSession查询相同数据
try(SqlSession session1 = factory.openSession()) {
    User user1 = session1.getMapper(UserMapper.class).selectById(1);
}

try(SqlSession session2 = factory.openSession()) {
    User user2 = session2.getMapper(UserMapper.class).selectById(1); // 会查询数据库
}
  1. 执行增删改操作
// 任何INSERT/UPDATE/DELETE操作都会清空当前SqlSession的一级缓存
mapper.updateUser(user); 
mapper.selectById(1); // 会重新查询数据库
  1. 手动清空缓存
sqlSession.clearCache(); // 显式清空一级缓存

2.4 一级缓存的配置选项

在mybatis-config.xml中可以通过以下参数调整:

<settings>
    <!-- 默认值为SESSION,缓存同一个SqlSession的所有语句 -->
    <!-- 设置为STATEMENT时,每次查询后都会清空缓存 -->
    <setting name="localCacheScope" value="SESSION|STATEMENT"/>
</settings>

三、二级缓存详解

3.1 二级缓存的基本特性

3.2 启用二级缓存的步骤

  1. 全局配置开启缓存(默认已开启):
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  1. 在Mapper XML中配置:
<mapper namespace="com.example.mapper.UserMapper">
    <cache/>
</mapper>
  1. 实体类实现Serializable接口:
public class User implements Serializable {
    //...
}

3.3 二级缓存的详细配置

完整缓存配置示例:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"
  type="org.mybatis.caches.ehcache.EhcacheCache"/>

参数说明: - eviction:缓存回收策略 - LRU(默认):最近最少使用 - FIFO:先进先出 - SOFT:软引用 - WEAK:弱引用 - flushInterval:刷新间隔(毫秒) - size:缓存对象最大数量 - readOnly:是否只读 - type:自定义缓存实现类

3.4 二级缓存的使用示例

// 第一个SqlSession
try(SqlSession session1 = factory.openSession()) {
    User user1 = session1.getMapper(UserMapper.class).selectById(1);
    session1.commit(); // 必须提交才会存入二级缓存
}

// 第二个SqlSession
try(SqlSession session2 = factory.openSession()) {
    User user2 = session2.getMapper(UserMapper.class).selectById(1); // 从二级缓存获取
}

3.5 二级缓存的注意事项

  1. 事务提交要求:只有SqlSession提交后,查询结果才会放入二级缓存
  2. 缓存同步问题:多个应用实例时需要考虑分布式缓存
  3. 数据一致性:其他系统修改数据库时可能导致缓存不一致

四、缓存使用最佳实践

4.1 适用场景分析

适合使用缓存的场景: - 读多写少的数据 - 实时性要求不高的数据 - 计算结果复杂的查询

不适合使用缓存的场景: - 财务交易等强一致性要求的场景 - 频繁更新的数据 - 数据量特别大的查询

4.2 性能优化建议

  1. 合理设置缓存大小
<cache size="1024"/> <!-- 根据内存情况调整 -->
  1. 使用第三方缓存实现
<cache type="org.mybatis.caches.redis.RedisCache"/>
  1. 部分方法禁用缓存
<select id="selectRealTimeData" flushCache="true" useCache="false">
    SELECT * FROM realtime_table
</select>

4.3 常见问题解决方案

缓存穿透问题: - 解决方案:对空结果也进行缓存

if(result == null) {
    // 缓存空对象,设置较短过期时间
    cache.put(key, NULL_OBJECT, 60); 
}

缓存雪崩问题: - 解决方案:设置不同的过期时间

<cache flushInterval="随机时间"/>

五、高级缓存应用

5.1 自定义缓存实现

  1. 实现Cache接口:
public class CustomCache implements Cache {
    private final String id;
    private Map<Object, Object> cache = new ConcurrentHashMap<>();
    
    // 实现所有接口方法...
}
  1. 在Mapper中指定:
<cache type="com.example.CustomCache"/>

5.2 使用Redis作为二级缓存

  1. 添加依赖:
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-redis</artifactId>
    <version>1.0.0-beta2</version>
</dependency>
  1. 配置redis.properties:
host=localhost
port=6379
password=
database=0
  1. Mapper配置:
<cache type="org.mybatis.caches.redis.RedisCache"/>

5.3 缓存监控与管理

  1. 通过JMX监控:
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("org.mybatis:type=Cache,id=com.example.mapper.UserMapper");
CacheStatisticsMXBean proxy = JMX.newMXBeanProxy(mBeanServer, name, CacheStatisticsMXBean.class);

System.out.println("命中率:" + proxy.getHitRatio());

六、总结与展望

6.1 缓存选择决策树

  1. 数据是否频繁更新? → 是:不使用缓存
  2. 是否需要跨会话共享? → 是:使用二级缓存
  3. 是否只当前会话使用? → 是:依赖一级缓存

6.2 MyBatis缓存的发展趋势

6.3 推荐学习资源

  1. MyBatis官方文档缓存章节
  2. 源码分析:PerpetualCache、CachingExecutor等类
  3. 集成Spring后的缓存行为变化

通过合理使用MyBatis的一二级缓存,可以显著提升应用性能。但需要注意缓存一致性问题,建议在开发测试阶段通过日志和监控工具验证缓存行为是否符合预期。 “`

注:本文实际约4500字,完整5000字版本可扩展以下内容: 1. 增加更多性能对比测试数据 2. 补充与Spring集成时的特殊配置 3. 添加实际项目中的缓存问题案例分析 4. 扩展分布式缓存解决方案的详细实现

推荐阅读:
  1. Mybatis一级缓存、二级缓存详讲
  2. 利用Hibernate怎么实现一级缓存和二级缓存

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mybatis

上一篇:怎么进行Server Name Indication的理论分析

下一篇:Java开源日志框架的原理是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》