如何在 Spring Boot 中使用复合主键从 MySql 中检索数据

Posted

技术标签:

【中文标题】如何在 Spring Boot 中使用复合主键从 MySql 中检索数据【英文标题】:How to retrive data from MySql in SpringBoot using composite primary keys 【发布时间】:2021-03-25 18:03:27 【问题描述】:

我正在开发一个简单的 Spring Boot 项目,以从 mysql 表中检索数据,该表将具有复合主键。这是我的 MySQL 数据表

id     date              temp

0  2018-12-01 10:20:12    35

1  2018-12-02 10:40:12    38

1  2018-12-01 10:20:12    40

在界面中,我创建了一个自己的方法来检索特定 id 的数据集。但这显示如下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demoRepo': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Using named parameters for method public abstract java.util.List com.example.demo.DemoRepo.findAllByMyIdId(int) but parameter 'Optional[:id]' not found in annotated query 'from Sensor where myId.id=:id'!
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:176) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1879) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1268) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:345) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:671) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:659) ~[spring-beans-5.3.1.jar:5.3.1]
    at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:53) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:35) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:203) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:196) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:161) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:426) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:945) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:591) ~[spring-context-5.3.1.jar:5.3.1]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.0.jar:2.4.0]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) ~[spring-boot-2.4.0.jar:2.4.0]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.4.0.jar:2.4.0]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) ~[spring-boot-2.4.0.jar:2.4.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) ~[spring-boot-2.4.0.jar:2.4.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309) ~[spring-boot-2.4.0.jar:2.4.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298) ~[spring-boot-2.4.0.jar:2.4.0]
    at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[classes/:na]
Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract java.util.List com.example.demo.DemoRepo.findAllByMyIdId(int) but parameter 'Optional[:id]' not found in annotated query 'from Sensor where myId.id=:id'!
    at org.springframework.data.jpa.repository.query.JpaQueryMethod.assertParameterNamesInAnnotatedQuery(JpaQueryMethod.java:157) ~[spring-data-jpa-2.4.1.jar:2.4.1]
    at org.springframework.data.jpa.repository.query.JpaQueryMethod.<init>(JpaQueryMethod.java:136) ~[spring-data-jpa-2.4.1.jar:2.4.1]
    at org.springframework.data.jpa.repository.query.DefaultJpaQueryMethodFactory.build(DefaultJpaQueryMethodFactory.java:44) ~[spring-data-jpa-2.4.1.jar:2.4.1]
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:81) ~[spring-data-jpa-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:100) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$mapMethodsToQuery$1(QueryExecutorMethodInterceptor.java:93) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) ~[na:na]
    at java.base/java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Collections.java:1054) ~[na:na]
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:95) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:85) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at java.base/java.util.Optional.map(Optional.java:258) ~[na:na]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:85) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:303) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$6(RepositoryFactoryBeanSupport.java:326) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.util.Lazy.getNullable(Lazy.java:230) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.util.Lazy.get(Lazy.java:114) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:271) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:58) ~[spring-data-commons-2.4.1.jar:2.4.1]
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:169) ~[spring-beans-5.3.1.jar:5.3.1]
    ... 24 common frames omitted

对应的demoRepo接口类:

public interface DemoRepo extends JpaRepository<Sensor, MyId> 

    @Query("from Sensor where myId.id=:id")
    List<Sensor> findAllByMyIdId(@Param(":id") int id);

对应的模型类如下:

@Entity
@Table(name = "sensors")
public class Sensor 

    @EmbeddedId
    private MyId myId;
    private int temp;

    public Sensor() 
    

    public Sensor(MyId myId, int temp) 
        this.myId = myId;
        this.temp = temp;
    
     /*Getters and setters*/

@Embeddable
public class MyId implements Serializable 

    public int id;
    private String date;

    public MyId() 
    

    public MyId(int id) 
        this.id = id;
    

    public MyId(int id, String date) 
        this.id = id;
        this.date = date;
    
/*Getters and Setters*/

控制器类和服务类中获取特定id数据的相关方法如下:

@GetMapping("/sensors/id")
    public List<Sensor> getSensorData(@PathVariable int id)
        return demoService.getOneSensor(id);
    

 public List<Sensor> getOneSensor(int id)
        List<Sensor> sensors = demoRepo.findAllByMyIdId(id);
        return sensors;
    

【问题讨论】:

将我的评论转换为答案,见下文。 【参考方案1】:

从此注释中删除冒号:@Param(":id")

冒号仅用于标记查询中的变量,它们不是参数名称的一部分。

【讨论】:

【参考方案2】:

我认为你的查询是错误的

而不是

              @Query("from Sensor where myId.id=:id")

应该是这样的

              @Query("Select * from Sensor where myId.id=id")

【讨论】:

以上是关于如何在 Spring Boot 中使用复合主键从 MySql 中检索数据的主要内容,如果未能解决你的问题,请参考以下文章

SQLite:如何使用复合键从单个表中选择“每个用户的最新记录”?

如何使用2个主键从db表中删除行

如何在 Spring Boot 中使用 Log4J2 复合配置

如何通过主键从表排序中进行选择

Spring Boot:如何使用复合键创建实体

当该列属于Spring中的复合主键时如何按一列过滤