【问题标题】:Hibernate null constraint violation on @Id with @GeneratedValue使用@GeneratedValue 对@Id 进行休眠空约束违规
【发布时间】:2012-05-26 13:10:59
【问题描述】:

我在 Play 上使用 Hibernate 4.1.3 (JPA)!框架。数据库是 PostgreSQL 8.4.2。架构是使用hibernate.hbm2ddl.auto="update" 生成的。

简短版:我有一个类有一个@Id 字段,即@GeneratedValue。有时,当persisting 时,我得到一个空列违规,为什么?


更多细节:

我有一个非常简单的类,我想将其保存到数据库中,如下所示:

@Entity
class MyObject {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long id;

    @NotNull
    public String email;

    public Integer total;
}

我通常创建一个 MyObject 的实例,我为 emailtotal 字段分配一个值,而 id 为空,我通过 EntityManager.persist() 保存它。 Hibernate 获取新对象的 id 并将其保存到 DB。

但有时,我会得到以下堆栈跟踪:

2012-05-19 00:45:16,335 - [ERROR] - from org.hibernate.engine.jdbc.spi.SqlExceptionHelper [SqlExceptionHelper.java:144] in play-akka.actor.actions-dispatcher-6 
ERROR: null value in column "id" violates not-null constraint

2012-05-19 00:45:16,350 - [ERROR] - from application in play-akka.actor.actions-dispatcher-6 


! @6ad7j3p8p - Internal server error, for request [POST /method] ->

play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: null value in column "id" violates not-null constraint]]

这怎么可能?如何追踪问题?

以下是 Hibernate 生成的相关 DDL:

CREATE TABLE myobject (
    id bigint NOT NULL,
    email character varying(255) NOT NULL,
    physical integer
);

CREATE SEQUENCE hibernate_sequence
    START WITH 1
    INCREMENT BY 1
    NO MAXVALUE
    NO MINVALUE
    CACHE 1;


ALTER TABLE ONLY dailydetailedscore
    ADD CONSTRAINT dailydetailedscore_pkey PRIMARY KEY (id);

【问题讨论】:

  • 添加 Hibernate 为您的数据库生成的 DDL。 GenerationType.AUTO 表示您已选择让 Hibernate 为您选择生成类型,这可能不是您打算做的。
  • @Perception:完成,感谢您指出。
  • 架构看起来不错。这可能是 Play 之间的交互问题!和 JPA。您是否尝试过使用标识列?
  • @Perception "GenerationType.AUTO 表示您已选择让 Hibernate 选择一种生成类型" 但它应该选择一个好的。引用 JPA 标准 [强调添加]:“持久性提供者应该为特定数据库选择 适当 策略。”违反 NOT NULL 约束的策略永远不会是“适当的”。这是否表明 Hibernate 存在缺陷?
  • 我在使用 Spring+Hibernate+Derby 时遇到了类似的问题。

标签: java hibernate postgresql annotations playframework


【解决方案1】:

在我的情况下,我使用 Identity 生成策略,并且在 Postgres 中设置了错误的数据类型。按照我执行的步骤来调试问题。

设置

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true 在 application.properties 中并删除表。

通过这个hibernate会根据你的数据类型自动为你创建模式。我注意到id字段的数据类型发生了变化。

现在,当我尝试任何发布请求时,一切正常。

【讨论】:

    【解决方案2】:

    使用Hibernate方法:-save(String entityName, Object object) 持久化给定的瞬态实例,首先分配一个生成的标识符。

    如果要保留用户定义的 Id,请不要使用:- @GeneratedValue(strategy=GenerationType.IDENTITY) 作为主键

    详情:- http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Session.html#save(java.lang.String

    【讨论】:

      【解决方案3】:

      OP 解决方案和 Matt 的解决方案都不适用于我的 PostgreSQL 9.3。

      但这一个有效:

      @SequenceGenerator(name="identifier", sequenceName="mytable_id_seq", allocationSize=1)  
      @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="identifier")
      

      mytable_id_seq 替换为生成您的 id 的序列的名称。

      【讨论】:

        【解决方案4】:

        试试注解@org.hibernate.annotations.GenericGenerator(name = “test-hilo-strategy”, strategy = “hilo”)

        @Id
        @org.hibernate.annotations.GenericGenerator(name=“hilo-strategy”, strategy = “hilo”)
        @GeneratedValue(generator = ”hilo-strategy”)
        

        正如上面提到的,AUTO 不会按照您的想法行事。它使用底层数据库来确定如何生成值。它可能会选择序列(用于 oracle)、标识列(用于 mssql)或其他特定于 db 的内容。

        这里的方法使用 Hibernate 提供的称为“hilo”的内部策略。

        请参阅 Hibernate 参考手册的第 5 章处理“生成器”,以完整描述每个提供的生成器的作用。

        【讨论】:

        • 实际上,AUTO 策略做了它应该在 Postgres 上做的事情(即,使用一个序列来生成唯一标识符)。事实证明,我的代码在 PostgreSQL 8.4.4 上运行良好,因此我认为这是一个特定于版本的错误。 hilo 生成器在 8.4.2 上工作得很好,所以我打算使用它。
        • 在 Postgres 8.4.20 中,我遇到了与使用 @GeneratedValue(strategy = GenerationType.AUTO) 的 OP 相同的错误,但此解决方案并未修复它。还有其他想法吗?
        猜你喜欢
        • 1970-01-01
        • 2016-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-16
        • 2019-08-08
        • 2020-03-28
        • 1970-01-01
        相关资源
        最近更新 更多