使用咖啡因在 Spring Boot 中缓存

Caching in Spring Boot with Caffeine

提问人:Nuñito Calzada 提问时间:10/17/2023 最后编辑:Anish B.Nuñito Calzada 更新时间:10/27/2023 访问量:346

问:

我有这个配置类:

@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);
    }
}

但是我总是在控制台中看到一个选择查询。但是我没有看到缓存日志。

java spring-boot spring-cache 咖啡因缓存

评论


答:

1赞 VonC 10/19/2023 #1

如果每次调用方法时都会在控制台中看到 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(..);
}
1赞 Dirk Deyne 10/21/2023 #2

使用您的配置,缓存应该可以正常工作。 如果失败,这是由于提供的代码以外的其他原因造成的。

在此处使用您的代码创建了一个工作演示:caffeine_cache

2赞 Anish B. 10/22/2023 #3

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'

这一次,该值存在于缓存中的键与 之前传递,并从缓存中获取值。

邮递员输出:

enter image description here