【问题标题】:Redis cache in Service class seems not workingService 类中的 Redis 缓存似乎不起作用
【发布时间】:2019-10-16 11:32:57
【问题描述】:

我正在学习 redis。现在面临redis缓存的问题。我正在调用具有相同值的服务类的方法,但似乎每次都会执行。

当我从 ThreadService 调用 EmployeeService 的 getEmployeesByClient() 方法时,我期待一个新客户端,我将看到日志getEmployeeByClient 的内部。但是对于下一次调用,我将从缓存中获取列表,然后它不会从存储库中提供数据。

但是每次我使用相同的参数调用 EmployeeService 的 getEmployeesByClient() 方法时,我都会得到日志 Inside of getEmployeeByClient。我在本节末尾也提供了我的日志。

我看到这个网站的一些问题是这样的: Spring boot caching in @Service class does not work

但还没有找到解决办法。

我正在提供我的相关代码:

我的 ThreadService 类:

@Service
@Slf4j
public class ThreadService implements Runnable {

    @Autowired
    private EmployeeService employeeService;

    public static boolean isRunning = true;

    @PostConstruct
    @Override
    public void run() {
        log.debug("Service Thread Started");
        while(isRunning) {
            log.debug("repository calling...");    
            List<Employee> employees = employeeService.getEmployeesByClient("FastVoiz");
            log.debug("Employee Size: " + employees.size());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                log.error("Exception: ", e);
            }
        }
    }
}

EmployeeService 类:

@Service
@Slf4j
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    @Cacheable(value = "employeeCache", key = "#client")
    public List<Employee> getEmployeesByClient(String client) {
        log.debug("Inside of getEmployeeByClient");
        return repository.findEmployeesByClient(client);
    }
}

RedisConfiguration 类:

@Configuration
@EnableCaching
@PropertySource("classpath:application.properties")
public class RedisConfiguration {
    @Autowired
    private Environment env;

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConf = new RedisStandaloneConfiguration();
        redisConf.setHostName(env.getProperty("spring.redis.host"));
        redisConf.setPort(Integer.parseInt(env.getProperty("spring.redis.port")));
        redisConf.setPassword(RedisPassword.of(env.getProperty("spring.redis.password")));
        return new LettuceConnectionFactory(redisConf);
    }
    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .disableCachingNullValues();
        return cacheConfig;
    }
    @Bean
    public RedisCacheManager cacheManager() {
        RedisCacheManager rcm = RedisCacheManager.builder(redisConnectionFactory())
                .cacheDefaults(cacheConfiguration())
                .transactionAware()
                .build();
        return rcm;
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demoNaz</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demoNaz</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <maven.test.skip>true</maven.test.skip>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--to run jar file-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <finalName>demoNaz</finalName>
    </build>

</project>

application.properties 文件:

#JPA configuration
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.show-sql=true
spring.data.jpa.repositories.enabled=true
spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.format_sql=true 

#datasource
spring.datasource.url=jdbc:postgresql://localhost:5432/testDB
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.initialization-mode=always
#spring.datasource.initialize=true
#spring.datasource.schema=classpath:/schema.sql
spring.datasource.continue-on-error=true
spring.datasource.platform=postgres

#redis
spring.redis.host=localhost
spring.redis.timeout=2000
spring.redis.password=password
spring.redis.port=6379

#redis cache manager configuration
spring.cache.type=redis
spring.cache.redis.cache-null-values=false
spring.cache.redis.time-to-live=600000
spring.cache.redis.use-key-prefix=true

#redis-lettuce configuration
spring.redis.lettuce.pool.max-active=7 
spring.redis.lettuce.pool.max-idle=7
spring.redis.lettuce.pool.min-idle=2
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.shutdown-timeout=200ms

#logging
logging.level.root=DEBUG
logging.file=demoApp.log

#others
spring.main.allow-bean-definition-overriding=true

这是我的一些日志:

2019-10-13 20:17:29.619 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : First line of thread
2019-10-13 20:17:29.619 DEBUG 12932 --- [           main] c.e.demoNaz.service.EmployeeService      : Inside of getEmployeeByClient
2019-10-13 20:17:29.620 DEBUG 12932 --- [           main] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-10-13 20:17:29.620 DEBUG 12932 --- [           main] o.h.q.c.internal.CriteriaQueryImpl       : Rendered criteria query -> select generatedAlias0 from Employee as generatedAlias0 where generatedAlias0.client=:param0
2019-10-13 20:17:29.620 DEBUG 12932 --- [           main] org.hibernate.SQL                        : select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
Hibernate: select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result set row: 0
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result row: EntityKey[com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Resolving associations for [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Done materializing entity [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:29.623 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : Employee Size: 1
2019-10-13 20:17:32.258 DEBUG 12932 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Pool stats (total=10, active=0, idle=10, waiting=0)
2019-10-13 20:17:34.623 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : First line of thread
2019-10-13 20:17:34.624 DEBUG 12932 --- [           main] c.e.demoNaz.service.EmployeeService      : Inside of getEmployeeByClient
2019-10-13 20:17:34.625 DEBUG 12932 --- [           main] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-10-13 20:17:34.625 DEBUG 12932 --- [           main] o.h.q.c.internal.CriteriaQueryImpl       : Rendered criteria query -> select generatedAlias0 from Employee as generatedAlias0 where generatedAlias0.client=:param0
2019-10-13 20:17:34.627 DEBUG 12932 --- [           main] org.hibernate.SQL                        : select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
Hibernate: select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
2019-10-13 20:17:34.628 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result set row: 0
2019-10-13 20:17:34.629 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result row: EntityKey[com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:34.630 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Resolving associations for [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:34.630 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Done materializing entity [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:34.631 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : Employee Size: 1
2019-10-13 20:17:39.633 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : First line of thread
2019-10-13 20:17:39.633 DEBUG 12932 --- [           main] c.e.demoNaz.service.EmployeeService      : Inside of getEmployeeByClient

【问题讨论】:

  • ThreadService类的作用是什么?
  • 现在只是为了测试目的运行 EmployeeService 方法。 @rokonoid vaia

标签: spring-boot caching redis


【解决方案1】:

首先,您不应该在 PostConstruct 阶段使用任何这些服务,因为此时您无法保证代理拦截器已完全启动。如果你必须做一些事情,在应用上下文初始化之后,尝试实现InitializingBean并重写afterPropertiesSet()方法,或者像ContextRefreshedEvent这样监听应用上下文事件强>。在那里开始你的线程。这将确保所有其他 bean 都已初始化。

现在,您的问题出现了,因为您的缓存拦截器未初始化。一种解决方法是手动初始化拦截器。为此,您可以这样做,

    @Configuration
    public class ConfigClass{
        @Autowired
        private CacheInterceptor cacheInterceptor;

        @PostConstruct
        public void init(){

            cacheInterceptor.afterSingletonsInstantiated();
        }
    }

这会奏效。

在你的依赖中添加 spring-boot-starter-cache https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-cache

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-19
    • 2011-09-03
    • 2011-03-09
    • 1970-01-01
    • 2016-12-28
    • 2020-09-10
    • 2016-04-25
    • 1970-01-01
    相关资源
    最近更新 更多