提问人:Nuñito Calzada 提问时间:10/17/2023 最后编辑:Anish B.Nuñito Calzada 更新时间:10/27/2023 访问量:346
使用咖啡因在 Spring Boot 中缓存
Caching in Spring Boot with Caffeine
问:
我有这个配置类:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
@Primary
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("dogsInHouse");
cacheManager.setCaffeine(Caffeine.newBuilder()
.initialCapacity(200)
.expireAfterAccess(Duration.ofDays(30))
.maximumSize(500));
return cacheManager;
}
}
在属性文件中:
spring.jpa.show-sql=true
在服务中:
@Service
@Transactional(readOnly = true)
@Slf4j
@CacheConfig(cacheNames = {"dogsInHouse"})
public class DogsInHouseService {
@Cacheable("dogsInHouse")
public DogsInHouse findDogHouseEnFromDB (String key) {
return dogsEnRepository.findByNameAndLangIs(key);
}
}
但是我总是在控制台中看到一个选择查询。但是我没有看到缓存日志。
答:
如果每次调用方法时都会在控制台中看到 select 查询,则表示缓存可能无法按预期工作。findDogHouseEnFromDB()
在阅读了 Lokesh Gupta 的“Caffeine Cache with Spring Boot”之后,出于调试目的,您可以添加一个端点或方法来检查缓存的内容,以确保条目按预期被缓存和逐出。
@GetMapping(value = "/inspectCache")
public void inspectCache() {
CaffeineCache caffeineCache = (CaffeineCache) cacheManager.getCache("dogsInHouse");
Cache<Object, Object> nativeCache = caffeineCache.getNativeCache();
for (Map.Entry<Object, Object> entry : nativeCache.asMap().entrySet()) {
System.out.println("Key = " + entry.getKey());
System.out.println("Value = " + entry.getValue());
}
}
注: 您可以将部分或全部配置移动到该文件中,而不是在 Java 配置文件中配置高速缓存属性。这可以简化配置并使其更易于管理。请参阅 JVM 语言的配置库application.properties
spring.cache.cache-names=dogsInHouse
spring.cache.caffeine.spec=initialCapacity=200,maximumSize=500,expireAfterAccess=720h
如果需要自定义缓存键生成,可以考虑实现自定义 KeyGenerator
或使用注释上的属性来指定缓存键的生成方式。key
@Cacheable
@Cacheable(value = "dogsInHouse", key = "#key")
public DogsInHouse findDogHouseEnFromDB (String key) {
return dogsEnRepository.findByNameAndLangIs(..);
}
使用您的配置,缓存应该可以正常工作。 如果失败,这是由于提供的代码以外的其他原因造成的。
在此处使用您的代码创建了一个工作演示:caffeine_cache
在 application.properties 中用于查看是否从缓存中选取了值。logging.level.org.springframework.cache=TRACE
注意:当您第一次点击该服务时,它将从数据库带来数据,并将数据放入缓存中,下次,它将从缓存中带来数据。
请在 Spring Boot App 中删除您不需要它。@CacheConfig
我已经使用MySQL进行演示。spring-data-jpa
使用相同的配置。只是添加以供参考。
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
@Primary
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("dogsInHouse");
cacheManager.setCaffeine(Caffeine.newBuilder()
.initialCapacity(200)
.expireAfterAccess(Duration.ofDays(30))
.maximumSize(500));
return cacheManager;
}
}
用于测试的 DogInHouse:
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DogInHouse {
@Id
@GeneratedValue
private int id;
@Column(name = "name")
private String name;
}
用于测试的 DogInHouseRepository:
public interface DogInHouseRepository extends JpaRepository<DogInHouse, Integer> {
}
用于测试的 My Service 类:
@Service
@Slf4j
public class DogsInHouseService {
@Autowired
private DogInHouseRepository dogsEnRepository;
@Cacheable(value = "dogsInHouse")
public Optional<DogInHouse> findDogHouseById(int key) {
return dogsEnRepository.findById(key);
}
}
application.properties 用于测试:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=Anish@123
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.springframework.cache=TRACE
我的 pom.xml 具有以下依赖项:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
</dependencies>
我的应用日志:
首次服务命中:
2023-10-21T22:22:16.575+05:30 TRACE 14989 --- [nio-8080-exec-3] o.s.cache.interceptor.CacheInterceptor : Computed cache key '1' for operation Builder[public java.util.Optional com.example.springbootmysql.DogsInHouseService.findDogHouseById(int)] caches=[dogsInHouse] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
2023-10-21T22:22:16.576+05:30 TRACE 14989 --- [nio-8080-exec-3] o.s.cache.interceptor.CacheInterceptor : No cache entry for key '1' in cache(s) [dogsInHouse]
2023-10-21T22:22:16.577+05:30 TRACE 14989 --- [nio-8080-exec-3] o.s.cache.interceptor.CacheInterceptor : Computed cache key '1' for operation Builder[public java.util.Optional com.example.springbootmysql.DogsInHouseService.findDogHouseById(int)] caches=[dogsInHouse] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
2023-10-21T22:22:16.587+05:30 DEBUG 14989 --- [nio-8080-exec-3] org.hibernate.SQL :
select
d1_0.id,
d1_0.name
from
dog_in_house d1_0
where
d1_0.id=?
目前,缓存中没有传递键的值, 因此,将通过 Hibernate 执行一个 select 查询以带来值 从数据库,该值由该键放入缓存中。
第二次服务命中:
2023-10-21T22:23:33.485+05:30 TRACE 14989 --- [nio-8080-exec-6] o.s.cache.interceptor.CacheInterceptor : Computed cache key '1' for operation Builder[public java.util.Optional com.example.springbootmysql.DogsInHouseService.findDogHouseById(int)] caches=[dogsInHouse] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
2023-10-21T22:23:33.490+05:30 TRACE 14989 --- [nio-8080-exec-6] o.s.cache.interceptor.CacheInterceptor : Cache entry for key '1' found in cache 'dogsInHouse'
这一次,该值存在于缓存中的键与 之前传递,并从缓存中获取值。
邮递员输出:
评论