下载工作台
Spring Boot Web 开发

Redis 缓存与异步任务

试读上半部分 · 解锁后可读全文

第 10 章 · Redis 缓存与异步任务

本章目标:在 shop-spring-demo 接入 Spring CacheRedis 缓存商品列表与详情;使用 @Async 异步发送通知、写审计日志;用 @Scheduled 实现订单超时关闭等定时任务;理解缓存失效、线程池配置与分布式环境下的注意点。

学时建议:4~5 小时(含 1 小时 Redis 联调)

前置ch09 日志与 AOP;ch05 JPA 查询;ch08 Profile 配置。


10.1 架构概览

┌──────────────┐                  ┌─────────────────┐
│  前端 SPA    │ ───────────────► │ shop-spring-demo │
└──────────────┘                  └────────┬─────────┘
              ┌────────────────────────────┼────────────────────────────┐
              ▼                            ▼                            ▼
         Redis 缓存                   @Async 线程池                  @Scheduled
    商品列表 TTL 300s              邮件/审计异步写                  每分钟扫超时订单
场景无 Redis/异步有 Redis/异步
首页商品列表每次 JOIN 查询缓存命中,毫秒级
下单后发通知同步 SMTP 阻塞 2s立即返回,后台发
未支付订单人工关单定时任务自动取消
Redis 地址教学统一 127.0.0.1:6379;禁止写入真实生产集群密码或内网拓扑。

10.2 Redis 本地环境

docker-compose.dev.yml

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data

volumes:
  redis_data:
docker compose -f docker-compose.dev.yml up -d redis
redis-cli ping   # PONG

10.3 依赖与配置

pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

application-dev.yml

spring:
  data:
    redis:
      host: 127.0.0.1
      port: 6379
      database: 0
      timeout: 3000ms
  cache:
    type: redis
    redis:
      time-to-live: 300000
      cache-null-values: false
      key-prefix: "shop:"

application-prod.yml

spring:
  data:
    redis:
      host: ${REDIS_HOST:redis.example.com}
      port: 6379
      password: ${REDIS_PASSWORD:}

10.4 启用缓存

@EnableCaching
@SpringBootApplication
public class ShopSpringDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShopSpringDemoApplication.class, args);
    }
}

可选:自定义 RedisCacheConfiguration Bean 统一 JSON 序列化:

@Bean
public RedisCacheConfiguration cacheConfiguration() {
    return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(5))
            .serializeValuesWith(
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer()));
}

10.5 @Cacheable / @CacheEvict 实战

ProductQueryService.java

@Service
public class ProductQueryService {

    private final ProductRepository repo;

    public ProductQueryService(ProductRepository repo) {
        this.repo = repo;
    }

    @Cacheable(value = "products", key = "#id")
    public Product findById(Long id) {
        return repo.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("商品不存在"));
    }

    @Cacheable(value = "productList", key = "#page + '_' + #size")
    public Page<Product> listPublished(int page, int size) {
        return repo.findByPublishedTrue(PageRequest.of(page, size));
    }
}

ProductAdminService.java 写操作清缓存:

@CacheEvict(value = {"products", "productList"}, allEntries = true)
public Product update(Long id, ProductUpdateDto dto) { /* 更新逻辑 */ }

@CacheEvict(value = "products", key = "#id")
public void delete(Long id) {
    repo.deleteById(id);
}
注解作用
@Cacheable先查缓存,无则执行方法并写入
@CachePut始终执行方法并更新缓存
@CacheEvict删除缓存项或清空 cache name
@Caching组合多个缓存操作

注意@Cacheable 同类内部自调用不走代理,需注入自身或拆 Service。


10.6 @EnableAsync 与线程池

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。