You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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',原因有两点:

  1. 方法名解析冲突:Spring Data JPA会自动解析接口方法名尝试生成查询语句,getTrainNameByID中的ID被识别为实体属性,但Train实体里的属性是小写id,导致解析失败。
  2. 自定义实现类命名不符合约定: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:20:25