Spring data rest 应用程序在实现 redis 缓存后没有从数据库中获取数据
Spring data rest application not getting data from database after implementing redis caching
我正在为我的 spring 数据剩余 (hal) api 实施 Redis 缓存。
需求:第一次调用数据库,对redis进行操作后,将所有数据缓存到redis。
像添加记录应该首先发生在缓存中,然后在事务中插入数据库。
我为 JpaRepository 之一实现了缓存,但是当我通过调用 /states 端点执行隐式 findAll 时,我没有得到任何记录,即使我在数据库中有 10k 条记录。
请大家帮忙!!
以下是我的配置:
MyServicesApplication.java
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import javax.persistence.EntityManagerFactory;
@SpringBootApplication
@EnableJpaAuditing
@EnableCaching
@EnableRedisRepositories
public class MyServicesApplication {
public static void main(String[] args) {
SpringApplication.run(PartnerServicesApplication.class, args);
}
@Bean
ApplicationRunner init(EntityManagerFactory entityManagerFactory) {
return args -> {
};
}
}
application.yml
springdoc:
api-docs:
path: /api-docs
swagger-ui:
path: /swagger-ui-custom.html
spring:
main:
allow-bean-definition-overriding: true
jackson:
serialization:
write-dates-as-timestamps: false
FAIL_ON_EMPTY_BEANS: false
date-format: MM/dd/yyyy
# time-zone: EST
datasource:
driverClassName: org.postgresql.Driver
password: mysecretpassword
url: jdbc:postgresql://localhost:5432/postgres?currentSchema=public
username: postgres
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
enable_lazy_load_no_trans: true
jdbc:
lob:
non_contextual_creation: true
max_size: 2
min_size: 2
temp:
use_jdbc_metadata_defaults: false
show-sql: true
cache:
redis:
cache-null-values: false
time-to-live: 600000
use-key-prefix: true
type: redis
redis:
host: localhost
port: 6379
password:
Jpa 实体 State.java
import org.springframework.data.redis.core.RedisHash;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.Optional;
@Entity
@Table(name = "my_state")
@RedisHash
public class State extends BaseAuditDetails {
@Id
@org.springframework.data.annotation.Id
@Column(name = "cde_st", nullable = false, length = 2)
private String cdeSt;
@Basic(optional = false)
@Column(name = "nam_st", nullable = false, length = 30)
private String namSt;
@Basic
@Column(name = "dte_inact", table = "state")
private LocalDate dteInact;
@Basic(optional = false)
@Column(name = "ind_dst_obsv", nullable = false)
private Character indDstObsv;
public String getCdeSt() {
return cdeSt;
}
public void setCdeSt(String cdeSt) {
this.cdeSt = cdeSt;
}
public Optional<String> getNamSt() {
return Optional.ofNullable(namSt);
}
public void setNamSt(String namSt) {
this.namSt = namSt;
}
public Optional<LocalDate> getDteInact() {
return Optional.ofNullable(dteInact);
}
public void setDteInact(LocalDate dteInact) {
this.dteInact = dteInact;
}
public Optional<Character> getIndDstObsv() {
return Optional.ofNullable(indDstObsv);
}
public void setIndDstObsv(Character indDstObsv) {
this.indDstObsv = indDstObsv;
}
}
MyStateRepository.java
import com.devstartshop.myapp.entities.State;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
import java.util.Optional;
/**
* Generated by Spring Data Generator on 16/03/2020
*/
@RepositoryRestResource
public interface MyStateRepository extends JpaRepository<State, String> {
@Override
@Cacheable(value = "state")
List<State> findAll();
@Override
@Cacheable(value = "state")
List<State> findAll(Sort sort);
@Override
@Cacheable(value = "state")
State getOne(String s);
@Override
@Cacheable(value = "state")
Page<State> findAll(Pageable pageable);
@Override
@Cacheable(value = "state")
Optional<State> findById(String s);
}
build.gradle
中的依赖项
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-core:1.1.49'
implementation 'org.springdoc:springdoc-openapi-ui:1.1.49'
implementation 'io.github.classgraph:classgraph:4.8.44'
implementation 'com.querydsl:querydsl-jpa:4.2.2'
// implementation 'org.slf4j:slf4j-log4j12:1.7.30'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.apache.commons:commons-pool2'
implementation 'org.springframework.data:spring-data-rest-hal-explorer'
implementation 'org.projectlombok:lombok:1.18.10'
implementation 'org.hibernate:hibernate-entitymanager:5.4.10.Final'
implementation 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final'
implementation 'com.github.kuros:random-jpa:1.0.3'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.0'
runtimeOnly 'com.h2database:h2:1.4.200'
runtimeOnly 'org.postgresql:postgresql:42.2.9'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'com.querydsl:querydsl-apt:4.2.2'
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
}
我发现使用@RedisHash 注解只会对Redis 数据库进行交易。
所以我采取了不同的方法,在所有 GET 调用上使用 @Cacheable,在所有其他负责更改数据库的调用上使用 @CacheEvict。
可能 @RedisHash 是为了将 Redis 用作事务数据库,它可以使用其他进程持久保存到持久性数据库,如 postgres。
我正在为我的 spring 数据剩余 (hal) api 实施 Redis 缓存。 需求:第一次调用数据库,对redis进行操作后,将所有数据缓存到redis。 像添加记录应该首先发生在缓存中,然后在事务中插入数据库。
我为 JpaRepository 之一实现了缓存,但是当我通过调用 /states 端点执行隐式 findAll 时,我没有得到任何记录,即使我在数据库中有 10k 条记录。
请大家帮忙!!
以下是我的配置:
MyServicesApplication.java
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import javax.persistence.EntityManagerFactory;
@SpringBootApplication
@EnableJpaAuditing
@EnableCaching
@EnableRedisRepositories
public class MyServicesApplication {
public static void main(String[] args) {
SpringApplication.run(PartnerServicesApplication.class, args);
}
@Bean
ApplicationRunner init(EntityManagerFactory entityManagerFactory) {
return args -> {
};
}
}
application.yml
springdoc:
api-docs:
path: /api-docs
swagger-ui:
path: /swagger-ui-custom.html
spring:
main:
allow-bean-definition-overriding: true
jackson:
serialization:
write-dates-as-timestamps: false
FAIL_ON_EMPTY_BEANS: false
date-format: MM/dd/yyyy
# time-zone: EST
datasource:
driverClassName: org.postgresql.Driver
password: mysecretpassword
url: jdbc:postgresql://localhost:5432/postgres?currentSchema=public
username: postgres
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
enable_lazy_load_no_trans: true
jdbc:
lob:
non_contextual_creation: true
max_size: 2
min_size: 2
temp:
use_jdbc_metadata_defaults: false
show-sql: true
cache:
redis:
cache-null-values: false
time-to-live: 600000
use-key-prefix: true
type: redis
redis:
host: localhost
port: 6379
password:
Jpa 实体 State.java
import org.springframework.data.redis.core.RedisHash;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.Optional;
@Entity
@Table(name = "my_state")
@RedisHash
public class State extends BaseAuditDetails {
@Id
@org.springframework.data.annotation.Id
@Column(name = "cde_st", nullable = false, length = 2)
private String cdeSt;
@Basic(optional = false)
@Column(name = "nam_st", nullable = false, length = 30)
private String namSt;
@Basic
@Column(name = "dte_inact", table = "state")
private LocalDate dteInact;
@Basic(optional = false)
@Column(name = "ind_dst_obsv", nullable = false)
private Character indDstObsv;
public String getCdeSt() {
return cdeSt;
}
public void setCdeSt(String cdeSt) {
this.cdeSt = cdeSt;
}
public Optional<String> getNamSt() {
return Optional.ofNullable(namSt);
}
public void setNamSt(String namSt) {
this.namSt = namSt;
}
public Optional<LocalDate> getDteInact() {
return Optional.ofNullable(dteInact);
}
public void setDteInact(LocalDate dteInact) {
this.dteInact = dteInact;
}
public Optional<Character> getIndDstObsv() {
return Optional.ofNullable(indDstObsv);
}
public void setIndDstObsv(Character indDstObsv) {
this.indDstObsv = indDstObsv;
}
}
MyStateRepository.java
import com.devstartshop.myapp.entities.State;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
import java.util.Optional;
/**
* Generated by Spring Data Generator on 16/03/2020
*/
@RepositoryRestResource
public interface MyStateRepository extends JpaRepository<State, String> {
@Override
@Cacheable(value = "state")
List<State> findAll();
@Override
@Cacheable(value = "state")
List<State> findAll(Sort sort);
@Override
@Cacheable(value = "state")
State getOne(String s);
@Override
@Cacheable(value = "state")
Page<State> findAll(Pageable pageable);
@Override
@Cacheable(value = "state")
Optional<State> findById(String s);
}
build.gradle
中的依赖项dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-core:1.1.49'
implementation 'org.springdoc:springdoc-openapi-ui:1.1.49'
implementation 'io.github.classgraph:classgraph:4.8.44'
implementation 'com.querydsl:querydsl-jpa:4.2.2'
// implementation 'org.slf4j:slf4j-log4j12:1.7.30'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.apache.commons:commons-pool2'
implementation 'org.springframework.data:spring-data-rest-hal-explorer'
implementation 'org.projectlombok:lombok:1.18.10'
implementation 'org.hibernate:hibernate-entitymanager:5.4.10.Final'
implementation 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final'
implementation 'com.github.kuros:random-jpa:1.0.3'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.0'
runtimeOnly 'com.h2database:h2:1.4.200'
runtimeOnly 'org.postgresql:postgresql:42.2.9'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'com.querydsl:querydsl-apt:4.2.2'
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
}
我发现使用@RedisHash 注解只会对Redis 数据库进行交易。 所以我采取了不同的方法,在所有 GET 调用上使用 @Cacheable,在所有其他负责更改数据库的调用上使用 @CacheEvict。
可能 @RedisHash 是为了将 Redis 用作事务数据库,它可以使用其他进程持久保存到持久性数据库,如 postgres。