Spring Data KeyValue中@KeySpace实体为何需要@Entity注解?
问题描述
在Spring 3.1 + Java 17环境下实践Spring Data KeyValue时发现:若不给标注@KeySpace的实体添加@Entity注解,就无法创建对应的Repository,报错信息如下:
2023-10-21T10:17:06.706-05:00 INFO 3536 --- [ main] .RepositoryConfigurationExtensionSupport : Spring Data Map - Could not safely identify store assignment for repository candidate interface com.example.demo.sql.Repo; If you want this repository to be a Map repository, consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
相关配置代码如下:
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>3.1.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>demo</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-keyvalue</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.properties配置
spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=sa spring.h2.console.enabled=true spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
实体与Repository代码
实体类
package com.example.demo.sql; import jakarta.persistence.Entity; import jakarta.persistence.Id; import org.springframework.data.keyvalue.annotation.KeySpace; @KeySpace // 移除@Entity注解就会触发报错 public class KeyValue { @Id public String key; public String value; }
Repository接口
package com.example.demo.sql; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface Repo extends CrudRepository<KeyValue, String> { }
启动类
package com.example.demo; import com.example.demo.sql.Repo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.data.map.repository.config.EnableMapRepositories; @SpringBootApplication @EnableMapRepositories public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public String bean(Repo repo) { return repo.toString(); } }
原因分析
这不是教程的错误,而是项目同时引入Spring Data JPA和Spring Data KeyValue两个模块后,Spring Data的仓库自动识别机制出现冲突:
- 实体无
@Entity注解时,JPA模块无法识别该实体,不会为其创建JPA仓库; - 但你的Repository继承的是通用
CrudRepository,而非Spring Data KeyValue专属的KeyValueRepository,导致Map Repository扩展无法确定该仓库应绑定到KeyValue存储; - 添加
@Entity注解后,JPA模块会接管该仓库并创建JPA实现类,因此不再报错,但此时实际使用的是JPA仓库而非KeyValue的Map仓库,与教程预期不符。
解决方案
有两种可行的解决方式:
让Repository继承KeyValue专属接口
修改Repository接口,直接继承KeyValueRepository而非通用的CrudRepository,让Spring Data明确识别这是一个KeyValue仓库,无需依赖@Entity注解:package com.example.demo.sql; import org.springframework.data.keyvalue.repository.KeyValueRepository; import org.springframework.stereotype.Repository; @Repository public interface Repo extends KeyValueRepository<KeyValue, String> { }明确指定Map仓库的扫描范围
若不想修改Repository的继承关系,可在@EnableMapRepositories中指定扫描包路径,同时排除JPA对该包的扫描以避免冲突:- 修改启动类注解:
@SpringBootApplication @EnableMapRepositories(basePackages = "com.example.demo.sql") @EnableJpaRepositories(excludeFilters = @Filter(type = FilterType.REGEX, pattern = "com.example.demo.sql.*")) public class DemoApplication { // 启动类原有内容不变 } - 同时移除实体类上的
@Entity注解。
- 修改启动类注解:
内容的提问来源于stack exchange,提问作者JustinKSU
相关产品推荐
相关产品推荐

