N

Norlcayn的博客

A text-focused Halo theme

  • 首页
  • 文章
  • 默认分类
  • 关于
主页 缓存优化
文章

缓存优化

发表于 2026-01-16 更新于 昨天
作者 Administrator
16~20 分钟 阅读

针对系统中访问频率很高的页面,常见的优化方案如下:

  1. 将页面做页面静态化处理
  2. 如果静态化之后依旧无法满足需求,可以将静态资源转移到CDN服务器
  3. 页面上变动的内容可以异步请求后端服务器获取数据,后端可以添加缓存来减轻数据库的压力
  4. 数据库方面可以通过合理的存储引擎选择、表字段设计、索引设计等进一步提高查询效率

页面静态化

什么是页面静态化?

页面静态化就是使用模板引擎技术(freemarker、Thymeleaf)将动态数据生成html静态网页

并将其与之使用的图片、css、js等静态资源存储到类似于Nginx之类支持高并发的存储中

因为纯静态网页通过类似Nginx这种服务器去加载要比去Tomcat加载快很多

CDN

内容分发网络(Content Delivery Network,CDN),是一种分布式的内容分发网,它需要在多个城市建立节点

然后将内容分发到各个城市的节点上,用户访问的时候就可以请求就近的服务器了

58cbeb3e-e951-42ec-8f3b-b15dfe615001

SpringCache

介绍

目前业界最主流的缓存技术就是Redis,而Java操作Redis目前有两种主流方案:

  • RedisTemplate:Spring提供的一个对象,内置了大量操作redis的方法,使用起来比较灵活
  • SpringCache:Spring提供的一套注解,可以基于方法级别对redis进行操作,使用起来非常简单

两种方式各有自己的优缺点,推荐以SpringCache为主,特殊情况下再采用RedisTemplate

SpringCache常用的注解有下面几个:

  • @EnableCaching:标注在启动类上,用来开启缓存注解功能
  • @Cacheable:主要标注在查询方法上,表示先从缓存中查询数据,如果有直接返回,如果没有再从数据库查询,返回的同时保存到缓存中一份
  • @CacheEvict:主要标注在新增、修改、删除方法上,用于将一条或多条数据从缓存中删除
  • @CachePut:用于更新缓存,它可以将方法的返回值放到缓存中

SpringCache支持多种缓存提供者,如Redis、EhCache、Caffeine等,可以自由切换他们

甚至可以不提供任何的缓存服务器,SpringCache依旧可以使用,他会使用内存做为缓存提供者

准备环境

单独提供一个环境来测试SpringCache

  1. 解压资料中提供的代码demo-springcache.zip,使用idea打开

7384f861-6a2c-4552-908c-52c076b32638

  1. 使用下面的语句创建用于测试的库表
CREATE DATABASE spring_cache_demo;
USE spring_cache_demo;

CREATE TABLE `user` (
  `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

缓存使用

使用SpringCache,主要就是学习如何来使用它提供的几个注解

@EnableCaching

@EnableCaching注解标注在启动类或者配置类上,用于开启基于注解的缓存功能

62023e5f-f037-4eeb-9fe1-12000de050ed

@CachePut

@CachePut:用于将方法的返回值放到缓存中,支持两个属性:

  • value: 缓存模块名称,每个模块下可以有很多key
  • key: 缓存的唯一标识,要注意的是它仅仅在一个value下保持唯一 也就是说value+key才能保证全局唯一
//@CachePut:将当前方法的返回值放入缓存中
//value:用于指定缓存内存区域的名称(划片)
//key:用于缓存数据的key,支持SPEL表达式
//  #user.id  表示获取当前方法参数user对象中的id属性值
//  #result.id 表示获取当前方法返回值对象中的id属性值
@CachePut(value = "userCache", key = "#result.id")
@PostMapping("/user")
public User save(@RequestBody User user) {
    userMapper.insert(user);
    return user;
}

当key用一个固定字符串时需要在双引号中用单引号括起来

@Cacheable

@Cacheable:主要标注在查询方法上,表示先从缓存中查询数据,如果有直接返回,如果没有再从数据库查询,返回的同时保存到缓存中一份

//@Cacheable:先查询缓存,没有再查数据库同步到缓存
@Cacheable(value = "userCache",key = "#id")
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
    return userMapper.getById(id);
}

在Cacheable注解中有两个属性可以指定条件进行缓存

  • condition:对方法参数进行判断,只缓存符合条件的
  • unless:对方法返回结果进行判断,只缓存不符合条件的

@CacheEvict

@CacheEvict:用于删除缓存,将一条或多条数据从缓存中删除

//@CacheEvict:清理指定key的缓存
@CacheEvict(value = "userCache", key = "#id")
@DeleteMapping("/user/{id}")
public void deleteById(@PathVariable Long id) {
    userMapper.deleteById(id);
}

//@CacheEvict:清理整个value区域所有缓存
@CacheEvict(value = "userCache", allEntries = true)
@DeleteMapping("/user")
public void deleteAll() {
    userMapper.deleteAll();
}

@Caching

注解**@Caching**可以将多个@Cacheable、@CacheEvict注解组合使用

@Caching(
        cacheable = {
                //返回数据为空,则缓存空值30分钟,这样可以避免缓存穿透
                @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key ="#regionId" ,
                        unless ="#result.size() > 0",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),

                //返回值不为空,则永久缓存数据
                @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key ="#regionId" ,
                        unless ="#result.size() == 0",cacheManager = RedisConstants.CacheManager.FOREVER)
        }
)

设置缓存时间

默认情况下,使用@Cacheable或者@CachePut放入缓存中的数据都是永久生效的,如何设置缓存的过期时间呢?

在@Cacheable、@CachePut注解中有一个属性为cacheManager,表示缓存管理器,通过它可以设置缓存过期时间

  1. 创建一个配置类,然后向容器中放入一个RedisCacheManager
@Configuration
public class SpringCacheConfig {
    @Bean
    public RedisCacheManager cacheManager30Minutes(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(30 * 60L));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }
}
  1. 在@Cacheable注解中使用cacheManager引用刚刚放入容器中的缓存管理器
@Cacheable(value = "userCache",key = "#id",cacheManager = "cacheManager30Minutes")
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id){
    return userMapper.getById(id);
}
云岚到家相关技术栈
Redis 缓存优化 Spring Cache
许可协议:  CC BY 4.0
分享

相关文章

1月 16, 2026

状态机

什么是状态机 需求说明 在订单模块中订单共设计了7种状态,如下图 订单会在多个状态间进行转换,这就需要开发人员都去记忆这些转换关系,这是非常麻烦的 if(订单状态 == 待支付){ //如果用户支付成功,执行此场景下的业务逻辑,更新订单状态为派单中 update(id,派单中) ) if(

1月 16, 2026

数据表设计规范

设计范式 数据库设计三范式: 第一范式:数据表中的每一列都是原子的,不可再拆分 第二范式:每张表中的一条记录只描述一个实体 第三范式:数据表中不要存在冗余字段(可以通过其他字段推导出的字段) 1)第一范式:数据表中的每一列都是原子的,不可再拆分 有一张用户考勤表设计如下 id 用户名 考勤时间 1

1月 16, 2026

缓存优化

针对系统中访问频率很高的页面,常见的优化方案如下: 将页面做页面静态化处理 如果静态化之后依旧无法满足需求,可以将静态资源转移到CDN服务器 页面上变动的内容可以异步请求后端服务器获取数据,后端可以添加缓存来减轻数据库的压力 数据库方面可以通过合理的存储引擎选择、表字段设计、索引设计等进一步提高查询

下一篇

状态机

上一篇

订单重复提交问题

最近更新

  • Hello Halo
  • 状态机
  • 数据表设计规范
  • 缓存优化
  • 事务失效

热门标签

Halo 异常处理 Redisson 并行 Vue 并发 递归 请求限流 SpringAMQP 类加载器

目录

©2026 Norlcayn的博客. 保留部分权利。

使用 Halo 主题 Chirpy