java - Spring JDBC : Auto generated id is not returned even though the row is inserted in table

标签 java spring h2 spring-jdbc

我正在尝试在表 Taco 中插入行并获取自动生成的 ID。

当我尝试在 saveTacoInfo 方法中使用 keyHolder.getKey().longValue() 获取 key 时,它抛出 NPE,但它显示了插入到 中的记录code>Taco 表,当我从 H2 控制台检查它时。

我正在使用 Spring Boot 2.1.0、Spring 5.1.2 和嵌入式 H2 数据库。我该如何解决这个问题?

H2 表架构:

create table if not exists Taco (
    id identity,
    name varchar(50) not null,
    createdAt timestamp not null
);

Jdbc 存储库实现:

package tacos.data;

import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
import java.util.Date;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import lombok.extern.slf4j.Slf4j;
import tacos.Taco;

@Slf4j
@Repository
public class JdbcTacoRepository implements TacoRepository {

    private JdbcTemplate jdbc;

    public JdbcTacoRepository(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    @Override
    public Taco save(Taco taco) {
        long tacoId = saveTacoInfo(taco);
        taco.setId(tacoId);

        for (String ingredient : taco.getIngredients()) {
            saveIngredientToTaco(ingredient, tacoId);
        }

        return taco;
    }

    private void saveIngredientToTaco(String ingredient, long tacoId) {
        jdbc.update("insert into Taco_Ingredients (taco, ingredient) values (?, ?)",
                tacoId, ingredient);

    }

    private long saveTacoInfo(Taco taco) {
        taco.setCreatedAt(new Date());

        log.info("taco: " + taco);

        PreparedStatementCreator psc = new PreparedStatementCreatorFactory(
                "insert into Taco (name, createdAt) values (?, ?)", 
                Types.VARCHAR, Types.TIMESTAMP
                ).newPreparedStatementCreator(
                        Arrays.asList(taco.getName(), new Timestamp(taco.getCreatedAt().getTime()))
                        );

        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbc.update(psc, keyHolder);

        log.info("keyholder: " + keyHolder.getKeyList());
        return keyHolder.getKey().longValue();
    }


}

堆栈跟踪:

2018-11-10 11:18:34.459  INFO 4024 --- [nio-8080-exec-3] tacos.data.JdbcTacoRepository            : taco: Taco(id=null, createdAt=Sat Nov 10 11:18:34 IST 2018, name=ccccccc, ingredients=[GRBF, CARN])
2018-11-10 11:18:34.542  INFO 4024 --- [nio-8080-exec-3] tacos.data.JdbcTacoRepository            : keyholder: []
2018-11-10 11:18:34.597 ERROR 4024 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
    at tacos.data.JdbcTacoRepository.saveTacoInfo(JdbcTacoRepository.java:63) ~[classes/:na]
    at tacos.data.JdbcTacoRepository.save(JdbcTacoRepository.java:31) ~[classes/:na]
    at tacos.data.JdbcTacoRepository$$FastClassBySpringCGLIB$$59d8a28e.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at tacos.data.JdbcTacoRepository$$EnhancerBySpringCGLIB$$996b212f.save(<generated>) ~[classes/:na]
    at tacos.web.DesignTacoController.processDesign(DesignTacoController.java:85) ~[classes/:na]

最佳答案

我刚刚遇到了完全相同的问题。

解决方法很简单:

h2 版本必须是 1.4.196,因为 1.4.197 会导致此问题。 只需在 pom.xml 中为 h2 依赖项指定此版本:

<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <scope>runtime</scope>
   **<version>1.4.196</version>**
</dependency>

同时将 ``parent``` 设置为 2.0.4.RELEASE 版本。这个版本可以解决这个问题。

保存pom.xml并检查maven依赖;确保 h2 和 spring boot 的版本已相应更改。

我相信这可以解决您的问题。

关于java - Spring JDBC : Auto generated id is not returned even though the row is inserted in table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53236596/

相关文章:

java - 根据请求参数 Autowiring 请求范围的 bean

java - H2 - Tomcat jdbc 连接池在达到最大限制后不回收连接

java - Java线程不会同步

java - 这个 Java 单例能否在 WebSphere 6 中重复重建?

java - 从 Java 字节码构建解析树/AST

java - Wicket:带有 ListView 的 FileUploadField

java - 为什么 Spring Boot 2.0 应用程序不运行 schema.sql?

java - 使用@Autowired获取正确的实例

database - 用Spring Boot创建h2数据库,如果不存在则不要删除。桌面应用程序

java - 如何解决 "Caused by: java.lang.IllegalStateException: The file is locked: nio:/Development/hiber/data/contactmgr.mv.db [1.4.192/7]"