Spring Boot:无法推断用于java.time.LocalDateTime

时间:2017-03-16 13:11:07

标签: spring spring-boot spring-jdbc jdbctemplate

我在 Spring Boot 项目中执行了以下方法(下面的完整JdbcInvoiceRepository类):

public int[] bulkSaveInvoices(List<Invoice> invoices){

    String insertSQL = "INSERT INTO invoices VALUES (:id, :exactIssueTime, :finalIssueTime, :issuer, :groupID)";
    SqlParameterSource[] sqlParams = SqlParameterSourceUtils.createBatch(invoices.toArray());

    int[] insertCounts = namedParameterJdbcTemplate.batchUpdate(insertSQL, sqlParams);

    return insertCounts;
}

我已经提供了转换器:

├── Invoice.java
├── InvoiceRepository.java
└── persistance
    ├── converters
    │   ├── LocalDateAttributeConverter.java
    │   └── LocalDateTimeAttributeConverter.java
    └── JdbcInvoiceRepository.java

LocalDateTime 的转换器:

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
        return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
    }
}

然而,当我在测试中执行它时,我不断收到错误:

  

org.springframework.jdbc.BadSqlGrammarException:   PreparedStatementCallback;错误的SQL语法[INSERT INTO发票   价值观(?,?,?,?,?)];嵌套异常是   org.postgresql.util.PSQLException:无法推断要用于的SQL类型   java.time.LocalDateTime的一个实例。使用setObject()和   显式类型值,用于指定要使用的类型。

     

在   org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:99)     在   org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)     在   org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)     在   org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)     在   org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649)     在   org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:662)     在   org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:950)     在   org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils.executeBatchUpdateWithNamedParameters(NamedParameterBatchUpdateUtils.java:40)     在   org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.batchUpdate(NamedParameterJdbcTemplate.java:335)     在   qbs.domain.model.persistance.JdbcInvoiceRepository.bulkSaveInvoices(JdbcInvoiceRepository.java:40)     在   qbs.domain.model.persistance.JdbcInvoiceRepository $$ FastClassBySpringCGLIB $$ 3c96bc2e.invoke()     在   org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)     在   org.springframework.aop.framework.CglibAopProxy $ CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)     在   org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)     在   org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)     在   org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)     在   org.springframework.aop.framework.CglibAopProxy $ DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)     在   qbs.domain.model.persistance.JdbcInvoiceRepository $$ EnhancerBySpringCGLIB $$ 20bcffdd.bulkSaveInvoices()     在qbs.QbsApplicationTests.fillDB(QbsApplicationTests.java:33)处   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     在   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:498)at   org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:50)     在   org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)     在   org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)     在   org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)     在   org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)     在   org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)     在   org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)     在org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)at   org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)     在   org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)     在org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:290)at at   org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:71)at at   org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)at at   org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:58)at at   org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:268)at at   org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)     在   org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)     在org.junit.runners.ParentRunner.run(ParentRunner.java:363)at   org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)     在org.junit.runner.JUnitCore.run(JUnitCore.java:137)at   com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)     在   com.intellij.rt.execution.junit.IdeaTestRunner $ Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)     在   com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)     在   com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     在   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:498)at   com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)   引起:org.postgresql.util.PSQLException:无法推断SQL类型   用于java.time.LocalDateTime的实例。使用setObject()   使用显式类型值指定要使用的类型。在   org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1051)     在   org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:454)     在   org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:238)     在   org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:169)     在   org.springframework.jdbc.core.BatchUpdateUtils.setStatementParameters(BatchUpdateUtils.java:65)     在   org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils.access $ 000(NamedParameterBatchUpdateUtils.java:32)     在   org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils $ 1.setValues(NamedParameterBatchUpdateUtils.java:48)     在   org.springframework.jdbc.core.JdbcTemplate $ 4.doInPreparedStatement(JdbcTemplate.java:960)     在   org.springframework.jdbc.core.JdbcTemplate $ 4.doInPreparedStatement(JdbcTemplate.java:950)     在   org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633)     ......还有47个

可能是什么问题以及如何解决这个问题?

编目: pom.xml中:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <!--For less boilerplate code-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!--JSR 330 for DI in Java - @Inject-->
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>


<repositories>
    <repository>
        <id>spring-releases</id>
        <url>https://repo.spring.io/libs-release</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-releases</id>
        <url>https://repo.spring.io/libs-release</url>
    </pluginRepository>
</pluginRepositories>

JdbcInvoiceRepository

@Repository
public class JdbcInvoiceRepository {

    @Inject
    private JdbcTemplate jdbcTemplate;
    @Inject
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    private SimpleJdbcInsert simpleJdbcInsert;

    @PostConstruct
    public void setupSimpleJdbcInsert(){
        simpleJdbcInsert =
                new SimpleJdbcInsert(jdbcTemplate).withTableName("invoices").usingGeneratedKeyColumns("id");
    }

    public int[] bulkSaveInvoices(List<Invoice> invoices){

        String insertSQL = "INSERT INTO invoices VALUES (:id, :exactIssueTime, :finalIssueTime, :issuer, :groupID)";
        SqlParameterSource[] sqlParams = SqlParameterSourceUtils.createBatch(invoices.toArray());

        int[] insertCounts = namedParameterJdbcTemplate.batchUpdate(insertSQL, sqlParams);

        return insertCounts;
    }

    public Long getInvoiceCount() {
        return jdbcTemplate.queryForObject("select count(*) from invoices",
                Long.class);

    }

}

EDIT Invoice.java

@Data
@AllArgsConstructor

@Entity
@Table(name = "invoices")
public class Invoice {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    @Column(name = "exact_iss_time")
    private LocalDateTime exactIssueTime;

    @Column(name = "final_iss_time")
    private LocalDateTime finalIssueTime;

    @Column(name = "issuer")
    private String issuer;

    @Column(name = "groupid")
    private Integer groupID;

    protected Invoice() {
    }

}

发票表定义:

    CREATE TABLE invoices (
  id      SERIAL PRIMARY KEY,
  exact_iss_time TIMESTAMP NOT NULL,
  actual_iss_time TIMESTAMP NOT NULL,
  issuer    TEXT NOT NULL,
  groupid   INTEGER NOT NULL
);

1 个答案:

答案 0 :(得分:0)

1)不要使用JDBC来尝试批量保存JPA实体

2)改为使用Spring Data JPA

3)将Spring Data Repository定义为:

public interface InvoiceRepository  extends JpaRepository<Invoice, Long> {}

4)调用save(存储库中的Iterable iterable方法,让JPA为您处理所有ORM任务。

e.g。 invoiceRepository.save(invoices)