添加自定义Repository实现后,Spring Boot报错找不到EntityManagerFactory Bean
问题背景
我有如下Repository定义:
UserRepository
@Repository public interface UserRepository extends CassandraRepository<User, String>, UserFilteringRepository { }
UserFilteringRepository
public interface UserFilteringRepository { List<User> findWithFilters(String userId); }
UserFilteringRepositoryImpl
public class UserFilteringRepositoryImpl implements UserFilteringRepository { @PersistenceContext private EntityManager entityManager; @Override public List<User> findWithFilters(String userId) { return null; } }
在添加UserFilteringRepository和UserFilteringRepositoryImpl之前,应用运行正常,Repository可以对实体执行创建、删除、查询等操作。但添加后,启动时出现如下异常:
Field userRepository in serverUserService required a bean of type 'javax.persistence.EntityManagerFactory' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'javax.persistence.EntityManagerFactory' in your configuration.
我使用spring-boot-starter Maven依赖,未显式引入任何Hibernate依赖。我理解Repository底层使用EntityManager,但单独使用Repository时运行正常,不清楚为何此时找不到该Bean。
已尝试的方案:
- 在Maven中指定不同的Hibernate版本
- 使用
@PersistenceUnit替代@PersistenceContext以直接获取EMF
问题原因与解决方案
核心原因
Spring Data Cassandra 不依赖JPA的EntityManager,它底层使用Cassandra原生驱动和Spring提供的CassandraTemplate处理数据访问,不会自动创建JPA的EntityManagerFactory Bean。
之前单独使用CassandraRepository时,Spring Data Cassandra自行处理数据操作,不需要JPA相关组件,因此运行正常。但你在UserFilteringRepositoryImpl中注入了EntityManager,触发Spring尝试初始化JPA上下文,而你的项目既没有引入JPA相关依赖(如spring-boot-starter-data-jpa),也没有配置JPA数据源,所以Spring找不到EntityManagerFactory Bean,抛出异常。
正确解决方案
要扩展Spring Data Cassandra的自定义查询,应该使用Cassandra专属API,替换EntityManager为CassandraTemplate:
修改UserFilteringRepositoryImpl:
public class UserFilteringRepositoryImpl implements UserFilteringRepository { private final CassandraTemplate cassandraTemplate; // 构造函数注入CassandraTemplate public UserFilteringRepositoryImpl(CassandraTemplate cassandraTemplate) { this.cassandraTemplate = cassandraTemplate; } @Override public List<User> findWithFilters(String userId) { // 示例:用CassandraTemplate执行自定义查询 Query query = Query.query(Criteria.where("userId").is(userId)); return cassandraTemplate.select(query, User.class); } }
补充说明
如果确实需要在项目中同时使用JPA和Cassandra,需要显式引入spring-boot-starter-data-jpa依赖并配置JPA数据源,但这不符合你当前仅扩展Cassandra查询的需求,使用CassandraTemplate是最合理的方案。
内容的提问来源于stack exchange,提问作者Andrew Orlowski

