如何强制Hibernate添加ID列来插入查询?

时间:2016-08-26 12:20:43

标签: mysql hibernate jpa spring-boot

我使用Spring Boot 1.4.0.RELEASE和依赖项中的以下数据库连接器

<!-- runtime dependencies -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

并且有一个实体类,其中包含GenerationType.AUTO ID生成政策(以下代码未完整)

@Entity
@Table(name = "scanner_run")
public class ScannerRun extends BaseObject {

    private Long id;

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    public Long getId() {
        return this.id;
    }
}

使用H2时,插入新实体没有问题

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

Hibernate生成insert into scanner_run (id, completed_ts, repository_id, started_ts, success) values (null, ?, ?, ?, ?)查询并创建新记录。

然而使用MySQL

spring.datasource.url=jdbc:mysql://localhost/db_dev?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&connectionCollation=utf8_general_ci
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

生成的查询为insert into scanner_run (completed_ts, repository_id, started_ts, success) values (?, ?, ?, ?) - ID不在查询中 - 失败

没有其他差异,仅在application.properties中更改以交换数据库。与早期版本的Hibernate和MySQL连接器相同的代码与MySQL的相同安装一起使用。 MySQL连接器解析为mysql:mysql-connector-java:jar:5.1.39

你能发现什么问题吗? 日志中的确切消息和例外是:

2016-08-26 14:38:03.964 DEBUG 32555 --- [  myScheduler-1] org.hibernate.SQL                        : insert into scanner_run (completed_ts, repository_id, started_ts, success) values (?, ?, ?, ?)
2016-08-26 14:38:03.967  WARN 32555 --- [  myScheduler-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1364, SQLState: HY000
2016-08-26 14:38:03.967 ERROR 32555 --- [  myScheduler-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : Field 'id' doesn't have a default value
2016-08-26 14:38:03.979 ERROR 32555 --- [  myScheduler-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task.

jvr.decrex.exception.ExecutionError: Failed to save ScannerRun{id=null, repository=/jv-ration/projects/jv-ration/deCrex/jvr-decrex/, startedTs=Fri Aug 26 14:38:03 CEST 2016, completedTs=null}
    at jvr.decrex.service.impl.GenericManagerImpl.insert(GenericManagerImpl.java:107)
    at jvr.decrex.scanner.service.impl.ScannerRunManagerImpl.createScan(ScannerRunManagerImpl.java:79)
.........
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
.........
    at jvr.decrex.scanner.dao.jpa.ScannerRunDaoJpa$$EnhancerBySpringCGLIB$$5e6c846a.insert()
    at jvr.decrex.service.impl.GenericManagerImpl.insert(GenericManagerImpl.java:105)
    ... 21 common frames omitted
Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
..........
    at com.sun.proxy.$Proxy126.persist(Unknown Source)
    at jvr.decrex.dao.jpa.GenericDaoJpa.insert(GenericDaoJpa.java:137)
    at jvr.decrex.dao.jpa.GenericDaoJpa$$FastClassBySpringCGLIB$$6605cd4e.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    ... 25 common frames omitted
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1078)
.........
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2376)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2360)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
    ... 58 common frames omitted

我尝试使用较早版本的5.1.27 mysql-connector-java版本,该版本适用于旧版本的Hibernate - 它会抛出相同的错误

1 个答案:

答案 0 :(得分:1)

您省略了数据库架构,因此需要进行大量的猜测。以下是可以说的: -

AUTO生成策略意味着JPA提供商可以选择它想要的任何策略。似乎对于MySQL,它使用AUTOINCREMENT列(相当于IDENTITY生成策略),对于H2,它可能使用SEQUENCE(猜测,因为你没有提供如何的细节)。也许你没有为MySQL的PK列定义AUTOINCREMENT?但在这种情况下你不能使用AUTO策略,而且你是。

您可以通过为要部署到的每个数据存储区提供 orm.xml 来处理它,然后您可以根据哪个数据存储区使用不同的生成策略。

或者选择TABLE生成策略,每次都会插入“id”列而不管数据存储区。

或者选择IDENTITY(当你使用PK的AUTOINIDEMENT列和PK的H2 IDENTITY列时)因为H2也会使用它(如果你还需要支持另一个数据存储,那么这显然不是一个选项没有这样的IDENTITY支持。