【问题标题】:Why does spring-boot-data-jdbc Query Methods require No Args Constructor为什么 spring-boot-data-jdbc 查询方法需要 No Args 构造函数
【发布时间】:2021-01-09 14:31:14
【问题描述】:

在我看来,实体上的所有查询方法,使用 spring-boot-data-jdbc,都需要有一个 No-Args 构造函数? 有什么原因吗? 这是一个给出此异常的简单示例。使用H2数据库

引起:org.springframework.beans.BeanInstantiationException: 无法实例化 [com.example.relationaldataaccess.Person]:否 找到默认构造函数;嵌套异常是 java.lang.NoSuchMethodException: com.example.relationaldataaccess.Person.()

典型的 Person 实体 -

import org.springframework.data.annotation.Id;

public class Person {
    

    @Id
    private long id;
    private  String firstName;
    private  String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

然后是仓库

public interface PersonRepository extends CrudRepository<Person, Long>{

    @Query("select * from person where first_name= :firstName")
    List<Person> findByFirstName(@Param("firstName") String firstName);

}

这是架构

create table person (
                        id integer identity not null primary key,
                        first_name varchar(30),
                        last_name varchar(30)
);

还有主应用

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private PersonRepository repository;


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... arg0) throws Exception {
        Person person = new Person("John", "Doe");
        repository.save(person);
        System.out.println("FIND BY FIRST_NAME ----->> "+ repository.findByFirstName("John"));
    }
}

application.properties 文件

spring.jpa.hibernate.ddl-auto=none
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:persondb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=test
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
logging.level.org.springframework.data=INFO

下面是应用程序的堆栈跟踪-

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at com.example.relationaldataaccess.Application.main(Application.java:21) ~[classes/:na]
Caused by: org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.example.relationaldataaccess.Person using constructor NO_CONSTRUCTOR with arguments 
    at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:65) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:87) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.data.relational.core.conversion.BasicRelationalConverter.createInstance(BasicRelationalConverter.java:147) ~[spring-data-relational-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.createInstanceInternal(BasicJdbcConverter.java:527) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.mapRow(BasicJdbcConverter.java:387) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.jdbc.core.convert.BasicJdbcConverter.mapRow(BasicJdbcConverter.java:323) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.jdbc.core.convert.EntityRowMapper.mapRow(EntityRowMapper.java:67) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.jdbc.repository.support.JdbcQueryLookupStrategy$PostProcessingRowMapper.mapRow(JdbcQueryLookupStrategy.java:152) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:679) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:694) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:176) ~[spring-jdbc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.data.jdbc.repository.query.AbstractJdbcQuery.lambda$getQueryExecution$2(AbstractJdbcQuery.java:127) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.execute(StringBasedJdbcQuery.java:85) ~[spring-data-jdbc-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor$QueryMethodInvoker.invoke(QueryExecutorMethodInterceptor.java:195) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at com.sun.proxy.$Proxy48.findByFirstName(Unknown Source) ~[na:na]
    at com.example.relationaldataaccess.Application.run(Application.java:28) ~[classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    ... 5 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.relationaldataaccess.Person]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.example.relationaldataaccess.Person.<init>()
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:146) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:62) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    ... 36 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.example.relationaldataaccess.Person.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3349) ~[na:na]
    at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553) ~[na:na]
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:139) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    ... 37 common frames omitted

2020-09-23 19:31:04.053  INFO 29948 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-09-23 19:31:04.059  INFO 29948 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 1

【问题讨论】:

  • 如果将@ConstructorProperties({"firstName", "lastName"}) 添加到构造函数,或者使用-parameters 标志编译时会发生什么?

标签: java spring-boot spring-data-jdbc


【解决方案1】:

我认为错误信息具有误导性。 Spring Data JDBC 不需要 No-Args-Constructor,但它需要一种方法来设置所有属性并且不访问私有字段。 毕竟它们是私有的,因此只能由拥有它们的类访问。 您的 id 字段不满足此要求。

执行以下操作之一应该可以解决问题:

  • 使id 字段至少包私有,即没有修饰符
  • id 字段添加一个setter。至少再次打包私有
  • id 添加到构造函数的参数中。
  • 添加一个将所有三个字段作为参数的构造函数。您可能需要将 @PersistenceConstructor 添加到该构造函数中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2021-08-12
    相关资源
    最近更新 更多