使用Spring Cache一定要注意这几个点

大家好,我是小趴菜,今天开始,我们系统的了解一下各种本地缓存框架的使用以及使用过程中需要注意的点

案例

js 复制代码
@EnableCaching   //启动类上加上开启缓存注解
@MapperScan("com.xpc.demo.mapper")
@RestController
@SpringBootApplication
@EnableTransactionManagement
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
js 复制代码
@Service
public class TcService {


    @Resource
    private TcMapper tcMapper;


    public void add(Tc tc) {
        tcMapper.insert(tc);
    }

    @CacheEvict(value = "user",key = "#tc.id")
    public void update(Tc tc) {
        Tc tcFromDb = tcMapper.selectById(tc.getId());
        tcFromDb.setName(tc.getName());
        tcMapper.updateById(tcFromDb);
    }

    public void deleteById(Long id) {
        tcMapper.deleteById(id);
    }

    @Cacheable(cacheNames = "user",key = "#id")
    public Tc queryById(Long id) {
        Tc tc = queryFromDb(id);
        return tc;
    }

    //这个方法主要是为了验证查询是否走了缓存,走了缓存那么就不会打印这一行数据
    private Tc queryFromDb(Long id) {
        Tc tc = tcMapper.selectById(id);
        System.out.println("执行数据库查询了");
        return tc;
    }
}
js 复制代码
@GetMapping("/queryById")
public Object test() {
    return tcService.queryById(1773593631234351105L);
}

启动项目访问: http://localhost:8080/queryById

浏览器刷新多次,还是只查询了一次数据库,说明我们的缓存有效了,查询是走了缓存的 我们发现使用Spring Cache很简单,但是它有什么缺点或者有什么需要注意的地方吗?

1:缓存没有失效时间

你会发现,只要你的服务没有停止,无论过了多长时间这个缓存都不会失效,Spring Cache底层实现是使用的是一个Map

所以只要你一旦这个数据进入到缓存了,那么只要服务没有停止,这个缓存就永远存在,所以当你缓存的数据越来越多,那么这个Map也会越来越大,到最后就会导致OOM,因为你除了停止服务,没有API提供给你去清除这个缓存

2:缓存Map容量问题

Spring Cache底层是使用Map来实现的,也没有API去删除这个缓存,那么当缓存的数据多了,这个Map会进行扩容,随着时间越来越久,Map成了大对象,就会导致OOM

3:服务集群部署,导致数据不一致

Spring Cache缓存的数据是存在本地的,如果你修改数据的时候是在服务A上执行的,这时候服务A上的缓存会更新,但是服务B上的缓存数据是没有更新的,所以查询的时候就会导致数据不一致,因为服务B上的缓存没有更新导致的

在开始的时候。两台服务器都有xpc这个缓存,并且数据都是 xpc:123,这时候客户来了一个修改请求,将这个值修改成 456

修改完以后变成下面这样,这时候客户端访问两台服务器返回的数据就会不一样了

4:没有事务导致缓存与数据库数据不一致

js 复制代码
@CacheEvict(value = "user",key = "#tc.id")
public void update(Tc tc) {
    Tc tcFromDb = tcMapper.selectById(tc.getId());
    tcFromDb.setName(tc.getName());
    tcMapper.updateById(tcFromDb);
    int i = 1/0;
}

我们在更新方法上会加上更新缓存的注解 @CacheEvict(value = "user",key = "#tc.id") 来达到更新后更新缓存的效果

但是,这时候如果你更新的方法上没有加事务,这时候数据库数据更新了,但是你的缓存是没有更新的

你会发现缓存与数据库数据不一致了

如果这时候有台服务器没有这个缓存,那么就能从数据库读到最新的数据,但是这台服务器就还是没有更新,就会造成数据不一致

相关推荐
好好沉淀6 分钟前
Apache 工具包(commons-io commons-lang3 )保姆介绍
java·ide
毕设源码-邱学长10 分钟前
【开题答辩全过程】以 服装购物平台为例,包含答辩的问题和答案
java·eclipse
黎燃13 分钟前
基于生产负载回放的数据库迁移验证实践:从模拟测试到真实预演【金仓数据库】
后端
多喝开水少熬夜21 分钟前
堆相关算法题基础-java实现
java·开发语言·算法
richxu2025100122 分钟前
Java开发环境搭建之 10.使用IDEA创建和管理Mysql数据库
java·ide·intellij-idea
7澄128 分钟前
Java 集合框架:List 体系与实现类深度解析
java·开发语言·vector·intellij-idea·集合·arraylist·linkedlist
行思理28 分钟前
IntelliJIdea 工具新手操作技巧
java·spring·intellijidea
文心快码BaiduComate32 分钟前
双十一将至,用Rules玩转电商场景提效
前端·人工智能·后端
拉不动的猪34 分钟前
关于scoped样式隔离原理和失效情况&&常见样式隔离方案
前端·javascript·面试
该用户已不存在38 分钟前
免费的 Vibe Coding 助手?你想要的Gemini CLI 都有
人工智能·后端·ai编程