spring boot 启动的时候将数据库里的分类信息写入redis

在 Spring Boot 启动时将数据库分类信息写入 Redis,推荐使用 ApplicationRunner 或 CommandLineRunner。它们会在 Spring 容器完全初始化、所有 Bean 就绪后执行,非常适合做缓存预热。

下面提供一份生产可用的完整方案:

📦 1. 核心实现代码

复制代码
复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class CategoryCacheWarmer implements ApplicationRunner {

    private final CategoryRepository categoryRepository;
    private final StringRedisTemplate stringRedisTemplate;
    private final ObjectMapper objectMapper;

    private static final String CATEGORY_CACHE_KEY = "app:categories";

    @Override
    public void run(ApplicationArguments args) {
        try {
            log.info("🚀 开始预热分类数据到 Redis...");
            
            List<Category> categories = categoryRepository.findAll();
            if (categories.isEmpty()) {
                log.warn("⚠️ 数据库中无分类数据,跳过 Redis 缓存初始化");
                return;
            }

            // 转为 JSON 字符串写入 Redis
            String json = objectMapper.writeValueAsString(categories);
            stringRedisTemplate.opsForValue().set(CATEGORY_CACHE_KEY, json);
            
            log.info("✅ 成功将 {} 条分类数据写入 Redis,Key: {}", categories.size(), CATEGORY_CACHE_KEY);
        } catch (Exception e) {
            // ⚠️ 建议不要直接抛出异常阻断应用启动,除非该缓存是强依赖
            log.error("❌ 初始化分类缓存失败,请检查数据库或 Redis 连接", e);
            // 如需阻断启动可取消注释: throw new RuntimeException("Category cache init failed", e);
        }
    }
}

⚙️ 2. 关键配置说明

Spring Boot 默认配置的 RedisTemplate 使用 JDK 序列化,会导致 Redis 中出现乱码。强烈建议使用 StringRedisTemplate + JSON 序列化:

复制代码
复制代码
// Spring Boot 已自动配置 StringRedisTemplate,通常无需额外配置
// 若需自定义 Jackson 序列化行为(如忽略 null、日期格式等),可注册 ObjectMapper Bean:
@Configuration
public class RedisConfig {
    @Bean
    public ObjectMapper redisObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null
        return mapper;
    }
}

🛡️ 3. 生产环境注意事项

问题 建议方案
Redis 宕机导致启动失败 使用 try-catch 降级记录日志,不阻断启动(如上代码)
每次启动都覆盖缓存? 启动时覆盖是合理的。若需保留运行期缓存,可先 hasKey() 判断,或使用版本号 Key:app:categories:v2
数据量大导致 OOM 或阻塞 分类数据通常较小。若超千条,建议分页查询或使用 Redis Pipeline 批量写入
运行期数据更新如何同步? 启动预热仅解决"冷启动"。CRUD 操作需通过 Cache Evict/Update 或监听 Binlog/MQ 保持缓存一致性
多实例部署重复写入 Redis 写入是幂等的,多实例同时执行无副作用。若需控制执行节点,可加分布式锁或配置 @ConditionalOnProperty

🔍 4. 为什么不用 @PostConstruct 或 @EventListener?

  • @PostConstruct:在 Bean 初始化后执行,但此时 Spring 上下文可能未完全就绪,DB/Redis 连接可能未建立。
  • @EventListener(ApplicationReadyEvent.class):功能等价于 ApplicationRunner,但 ApplicationRunner 接口更语义化,且能方便传入启动参数。

📌 5. 扩展:按需开关预热

可通过配置文件控制是否开启:

复制代码
复制代码
app:
  cache:
    warmup:
      enabled: true
      category: true
复制代码
复制代码
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "app.cache.warmup", name = "enabled", havingValue = "true", matchIfMissing = true)
public class CategoryCacheWarmer implements ApplicationRunner {
    // ... 同上文
}

💡 最佳实践总结 :启动预热适合读多写少、变更频率低的基础数据(如分类、字典、配置)。对于高频变更数据,应采用"缓存穿透防护 + 主动更新/过期策略"代替启动加载。

相关推荐
Decay__3 小时前
VMware 安装 SQL Server 双节点 AlwaysOn 可用性组教程 —— WSFC、AG 与侦听器完整部署(系列核心篇)
运维·数据库·sql·mysql·架构
茶栀(*´I`*)4 小时前
SQL 性能分析:从慢查询日志到执行计划的完整定位方法
数据库·sql
艺杯羹5 小时前
1Panel 装好后 ufw 仍是 inactive:一次服务器安全盲区复盘
服务器·数据库·安全·网络安全·系统架构·实战·1panel
code2cat5 小时前
【随笔】MCP工具重试:任务已经创建,响应丢了怎么办
数据库·mcp
Star(up up up)6 小时前
Redis Windows 安装教程:使用Windows 的 Redis 压缩包
redis·笔记·学习·程序人生·云原生·学习方法·改行学it
wuyk5557 小时前
Spider-第10讲-SQLite持久化与去重
数据库·爬虫·sqlite
乌暮9 小时前
Spring AOP 与 Spring 事务:用大白话彻底理解原理与实践
java·数据库·spring boot·后端·sql·学习·spring
小此方9 小时前
Re:Mysql数据库基础篇(十二):什么是事务、事务解决了什么问题、事务的四大属性、事务的操作方式
数据库·mysql
flash俊杰11 小时前
v0.5-01 让桌面 AI 助手记得住:预算组装、递归摘要、长期记忆与评估基线
数据库·安全·架构
2501_9339232511 小时前
redis:string类型常见命令
数据库·redis·缓存