Spring Boot自定义Repository创建失败,抛出UnsatisfiedDependencyException
Spring Data JPA自定义仓库继承后抛出UnsatisfiedDependencyException问题解决
问题背景
原本TrainRepository继承JpaRepository<Train, Long>运行正常,新增CustomRepository并让TrainRepository继承该接口后,Spring抛出UnsatisfiedDependencyException。
相关代码
TrainRepository
@Repository public interface TrainRepository extends JpaRepository<Train, Long>, CustomRepository { @Query("select new ua.nulp.company.traincompany.dto.TrainsDto(t.id,t.name,t.trainType) from Train t") List<TrainsDto> findTrains(); @Query("select new ua.nulp.company.traincompany.dto.TrainDto(t.name,t.trainType) from Train t where t.id=:id") TrainDto findDtoTrainById(@Param("id") Long id); @Query("select distinct t.trainType from Train t") List<TrainType> getTrainTypes(); @Query(value = "SELECT t.name as name, sum(c.number_seats) as seats FROM train t JOIN train_car c ON " + "t.id = c.train_id WHERE t.id = 2 GROUP BY t.name;", nativeQuery = true) TrainSeatsDto getAmountPassengersSeats(@Param("id") Long id); }
CustomRepository
public interface CustomRepository { String getTrainNameByID(Long id); }
CustomRepositoryImp
public class CustomRepositoryImp implements CustomRepository { @PersistenceContext private EntityManager entityManager; @Override @Transactional(readOnly = true) public String getTrainNameByID(Long id) { return entityManager.createQuery("SELECT t.name FROM Train t WHERE t.id =:id", String.class) .setParameter("id", id) .getSingleResult(); } }
异常信息
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2022-11-19 21:17:13.006 ERROR 15300 --- [ main] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'trainController' defined in file [C:\Users\ASUS\OneDrive\Документи\Java\enterprise\programs\TrainCompany\target\classes\ua\nulp\company\traincompany\controller\TrainController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'trainRepository' defined in ua.nulp.company.traincompany.repository.TrainRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.lang.String ua.nulp.company.traincompany.repository.CustomRepository.getTrainNameByID(java.lang.Long); Reason: Failed to create query for method public abstract java.lang.String ua.nulp.company.traincompany.repository.CustomRepository.getTrainNameByID(java.lang.Long)! No property 'ID' found for type 'Train' Did you mean ''id''; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.lang.String ua.nulp.company.traincompany.repository.CustomRepository.getTrainNameByID(java.lang.Long)! No property 'ID' found for type 'Train' Did you mean ''id'' at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.23.jar:5.3.23] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.5.jar:2.7.5] at ua.nulp.company.traincompany.TrainCompanyApplication.main(TrainCompanyApplication.java:10) ~[classes/:na]
问题分析
异常核心信息:No property 'ID' found for type 'Train',原因有两点:
- 方法名解析冲突:Spring Data JPA会自动解析接口方法名尝试生成查询语句,
getTrainNameByID中的ID被识别为实体属性,但Train实体里的属性是小写id,导致解析失败。 - 自定义实现类命名不符合约定:Spring Data JPA默认要求自定义仓库实现类命名为
[主仓库接口名]Impl(比如主仓库是TrainRepository,实现类需叫TrainRepositoryImpl)。当前CustomRepositoryImp的命名不符合约定,JPA无法找到自定义方法的实现,转而尝试自动生成查询,最终触发错误。
解决方案
方案一:修正实现类命名(推荐)
按照Spring Data JPA约定,将自定义实现类名称改为TrainRepositoryImpl,同时移除CustomRepository上的@Repository注解(主仓库TrainRepository已被扫描,自定义接口无需额外注解):
@Transactional(readOnly = true) public class TrainRepositoryImpl implements CustomRepository { @PersistenceContext private EntityManager entityManager; @Override public String getTrainNameByID(Long id) { return entityManager.createQuery("SELECT t.name FROM Train t WHERE t.id =:id", String.class) .setParameter("id", id) .getSingleResult(); } }
方案二:修改方法名适配JPA解析规则
将CustomRepository中的方法名从getTrainNameByID改为getTrainNameById,让JPA能正确识别实体的id属性,同时确保实现类命名符合约定:
public interface CustomRepository { String getTrainNameById(Long id); }
方案三:指定实现类后缀(可选)
如果想保留CustomRepositoryImp的命名,可在Spring Boot启动类上添加@EnableJpaRepositories注解指定实现类后缀:
@SpringBootApplication @EnableJpaRepositories(basePackages = "ua.nulp.company.traincompany.repository", repositoryImplementationPostfix = "Imp") public class TrainCompanyApplication { public static void main(String[] args) { SpringApplication.run(TrainCompanyApplication.class, args); } }
内容的提问来源于stack exchange,提问作者Denys Ryhal
相关产品推荐
相关产品推荐

