Mybatis一级缓存和二级缓存,前后端代码演示
文章目录
场景
在查询较多的应用场景,如火车站点查询,如果每次查询都要访问数据库,则系统效率较低,因此可以用到Mybatis的缓存机制。
实验简单模拟:
- 查询业务逻辑:
public List<TrainQueryResp> queryAll() {
List<Train> trainList = selectAll();
LOG.info("再查一次");
trainList = selectAll();
return BeanUtil.copyToList(trainList, TrainQueryResp.class);
}
public List<Train> selectAll() {
TrainExample trainExample = new TrainExample();
trainExample.setOrderByClause("code asc");
return trainMapper.selectByExample(trainExample);
}
- 接口
@GetMapping("/query-all")
public CommonResp<List<TrainQueryResp>> queryList() {
List<TrainQueryResp> list = trainService.queryAll();
return new CommonResp<>(list);
}
- 未开启Mybatis缓存的执行效果
控制台打印了两次Sql,说明按照逻辑查询了两次
开启Mybatis一级缓存
一级缓存是 MyBatis 中默认开启的,在一个 SqlSession 内有效。
1. 增加注解 @Transactional
// 加上事务注解,开启一级缓存
@Transactional
public List<TrainQueryResp> queryAll() {
List<Train> trainList = selectAll();
LOG.info("再查一次");
trainList = selectAll();
return BeanUtil.copyToList(trainList, TrainQueryResp.class);
}
2. 查询结果
可见第二次查询就不再查询数据库了,而是直接缓存读取
一级缓存可以帮助减少重复的数据库查询
- 若要关闭一级缓存,则添加以下配置:
# 配置为statement,即关闭一级缓存
mybatis.configuration.local-cache-scope=statement
3. 失效条件
对数据库信息进行了增删改的修改,就会再次查询数据库
开启Mybatis二级缓存
二级缓存的作用域是 mapper 级别,多个 SqlSession 可以共享二级缓存中的数据。
1. 修改Mapper文件
在对应的mapper文件中添加以下标签
<cache></cache>
2. 实体类实现序列化
在实体类上添加implements Serializable
:
public class Train implements Serializable {
以上两步修改即开启了Mybatis二级缓存
3. 实现效果
第一次调用接口:
第一次还未缓存,命中失败,去查数据库
第二次调用接口:
此时命中缓存,一次Sql都没有打印,说明二次缓存成功,没有去查数据库
4. 分布式环境二级缓存的缺陷
在分布式环境中,多个节点都可能拥有二级缓存。当一个节点对数据库中的数据进行修改时,需要一种机制来通知其他节点更新或清除其二级缓存中的相关数据。
例如,在一个电商系统中,商品库存数据存储在数据库中,多个应用服务器节点都有二级缓存来缓存商品库存信息。如果节点 A 处理了一个商品销售订单并更新了库存,它需要及时告知节点 B 和节点 C 等其他节点清除对应的库存缓存数据,否则这些节点可能会继续使用旧的库存数据,导致数据不一致。