Spring Boot中如何在启动时用Caffeine Cache调用@Cacheable预加载数据库数据?
嘿,作为缓存新手,咱们一步步来搞定这个需求——Spring Boot启动时把数据库数据塞进Caffeine缓存,之后直接读缓存不用碰DAO。别担心,每一步都很接地气,跟着做就行!
首先得让项目支持Spring Cache和Caffeine,咱们用Maven或者Gradle都可以:
Maven(pom.xml)
<dependencies> <!-- Spring Boot Cache 起步依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!-- Caffeine 缓存实现 --> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency> <!-- 数据库相关依赖(比如Spring Data JPA,根据你的实际情况调整) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>
Gradle(build.gradle)
dependencies { implementation 'org.springframework.boot:spring-boot-starter-cache' implementation 'com.github.ben-manes.caffeine:caffeine' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2' }
在application.yml里配置缓存的基础参数,新手不用搞太复杂,先配实用的:
spring: cache: type: caffeine caffeine: spec: initialCapacity=50,expireAfterAccess=3600s # 初始容量50,访问后1小时过期 cache-names: usersCache # 提前定义缓存名称,后面和@Cacheable对应
简单解释下:
initialCapacity:缓存初始能存多少条数据,避免频繁扩容expireAfterAccess:数据多久没人访问就自动过期,这里设的1小时cache-names:给咱们的缓存起个专属名字,后面要用它定位缓存
在你的Spring Boot启动类上加@EnableCaching注解,告诉Spring:“嘿,我要启用缓存功能啦!”
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching // 关键注解,必须加! public class CacheDemoApplication { public static void main(String[] args) { SpringApplication.run(CacheDemoApplication.class, args); } }
咱们分三层来写:DAO(负责查数据库)、Service(加缓存注解)、启动触发逻辑(提前加载缓存)。
第一步:DAO层(从数据库拿数据)
假设咱们要缓存用户数据,写个简单的DAO接口:
import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.entity.User; public interface UserDao extends JpaRepository<User, Long> { // 用JPA自带的findAll,自动实现从数据库查询所有用户 }
对应的User实体类(简单示例):
import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // 记得补全构造方法、getter、setter哦 }
第二步:Service层(加@Cacheable核心注解)
这里是实现缓存的关键!在Service的方法上加上@Cacheable,指定咱们之前配置的缓存名usersCache。这样第一次调用这个方法时,会执行方法体(查数据库),然后把结果存进缓存;之后再调用,直接从缓存拿数据,完全不会碰数据库。
import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserService { private final UserDao userDao; // 构造注入DAO public UserService(UserDao userDao) { this.userDao = userDao; } // @Cacheable:第一次调用查数据库,之后直接读缓存 // value指定缓存名称,和配置文件里的cache-names对应 @Cacheable(value = "usersCache") public List<User> getAllUsers() { System.out.println("正在从数据库查询用户数据..."); // 加个日志,方便验证缓存是否生效 return userDao.findAll(); } }
第三步:启动时主动触发缓存加载
现在要让Spring Boot启动时就调用getAllUsers(),把数据提前塞进缓存。咱们用ApplicationRunner来实现——这是Spring提供的、启动完成后自动执行代码的接口。
可以直接在启动类里加个Bean:
import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableCaching public class CacheDemoApplication { public static void main(String[] args) { SpringApplication.run(CacheDemoApplication.class, args); } // 启动时执行这个方法,触发缓存加载 @Bean public ApplicationRunner cacheLoader(UserService userService) { return args -> { System.out.println("启动时加载用户数据到缓存..."); userService.getAllUsers(); // 调用带@Cacheable的方法,触发缓存写入 }; } }
写个简单的Controller来测试:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping("/users") public List<User> getUsers() { return userService.getAllUsers(); } }
现在启动项目,你会看到控制台输出:
启动时加载用户数据到缓存... 正在从数据库查询用户数据...
这说明启动时已经调用了DAO,把数据存进缓存了。
然后你多次访问http://localhost:8080/users,控制台不会再输出“正在从数据库查询用户数据...”,说明每次都是直接从缓存拿数据,完美实现需求!
@Cacheable的value必须和配置文件里的cache-names对应,不然Spring找不到对应的缓存- 如果你的方法有参数,缓存默认会用参数作为key,比如
getUserById(Long id),不同的id会存在不同的缓存条目里 - 如果数据库数据更新了,你需要用
@CacheEvict(清除缓存)或者@CachePut(更新缓存)来同步缓存数据,不然会读到旧数据(这个咱们以后再慢慢研究,先搞定当前需求就好)
内容的提问来源于stack exchange,提问作者ulagan

