Spring Boot Redis缓存测试异常:findAll方法未被缓存重复调用
Redis缓存未生效:多次调用getStudents()重复触发数据库查询
我正在学习Spring Boot,搭建了一个学生信息管理的RESTful API。除了StudentConfigTest.java中的缓存测试外,其余测试均正常运行。在这个测试中,我调用studentService.getStudents()两次,预期首次调用会触发studentRepository.findAll()查询数据库并将结果存入Redis缓存,第二次调用直接从缓存返回数据,但实际studentRepository.findAll()被重复调用了多次,缓存没有生效。
以下是所有相关代码文件:
StudentConfigTest.java
package com.example.springApi.student; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest; import org.springframework.cache.CacheManager; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Import; import java.util.Arrays; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @EnableCaching @DataRedisTest @Import(StudentService.class) public class StudentConfigTest { @MockBean private StudentRepository studentRepository; @Autowired private StudentService studentService; @Autowired private CacheManager cacheManager; @BeforeEach void setUp() { cacheManager.getCache("studentCache").clear(); } @Test void givenRedisCaching_whenGetStudents_thenStudentsReturnedFromCache() { // Given List<Student> students = Arrays.asList( new Student("Alice", 25, "alice@example.com"), new Student("Bob", 30, "bob@example.com") ); given(studentRepository.findAll()).willReturn(students); // When List<Student> studentsCacheMiss = studentService.getStudents(); List<Student> studentsCacheHit = studentService.getStudents(); // Then assertThat(studentsCacheMiss).isEqualTo(students); assertThat(studentsCacheHit).isEqualTo(students); // Verify that the repository method was called only once during cache miss verify(studentRepository, times(1)).findAll(); // Additional assertion to check caching behavior assertThat(studentService.getStudents()).isEqualTo(students); // Cache hit again, should return the same list } }
StudentService.java
@Service public class StudentService { private final StudentRepository studentRepository; @Autowired public StudentService(StudentRepository studentRepository) { this.studentRepository = studentRepository; } @Cacheable("studentCache") public List<Student> getStudents() { return studentRepository.findAll(); } public void addNewStudent(Student student){ Optional existsEmail = studentRepository.selectExistsEmail(student.getEmail()); if (existsEmail.isPresent()) { throw new IllegalStateException("Email " + student.getEmail() + " taken"); } if (!isValidName(student.getName())) { throw new IllegalStateException("name can only contain letters"); } studentRepository.save(student); } public boolean isValidName(String studentName) { char[] chars = studentName.toCharArray(); System.out.println(chars); for (char c: chars){ if (!Character.isLetter(c)) { return false; } } return true; } public void deleteStudent(Long studentId) { boolean exists = studentRepository.existsById(studentId); if (!exists) { throw new IllegalStateException("student with id " + studentId + " does not exist"); } studentRepository.deleteById(studentId); } }
StudentConfig.java
package com.example.springApi.student; import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import java.time.Duration; @Configuration public class StudentConfig { @Bean public RedisCacheConfiguration cacheConfiguration() { return RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(60)) .disableCachingNullValues() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); } @Bean public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() { return (builder) -> builder .withCacheConfiguration("studentCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10))); } }
StudentRepository.java
package com.example.springApi.student; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository public interface StudentRepository extends JpaRepository<Student, Long> { @Query("SELECT s FROM Student s WHERE s.email = ?1") Optional selectExistsEmail(String email); }
application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/student spring.datasource.username=postgres spring.datasource.password=password spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.format_sql=true server.error.include-message=always spring.data.redis.host=localhost spring.data.redis.port=6379
内容的提问来源于stack exchange,提问作者jalen002
相关产品推荐
相关产品推荐

