hibernate无法获得下一个序列值

use*_*587 44 postgresql hibernate

我有gwt应用程序连接到后端的postgres DB,以及一个java类'判断'映射数据库中的表'判断',当我试图将判断持久化到db时,它抛出了以下错误:

Caused by: org.hibernate.exception.SQLGrammarException: could not get next sequence value
...
Caused by: org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist
Run Code Online (Sandbox Code Playgroud)

我的审判级看起来像这样

@Entity
@Table(name = "JUDGEMENTS")
public class Judgement implements Serializable, Cloneable {

    private static final long serialVersionUID = -7049957706738879274L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "JUD_ID")
    private Long _judId;
...
Run Code Online (Sandbox Code Playgroud)

我的表判断是:

   Column    |            Type             |                        Modifiers                        
-------------+-----------------------------+---------------------------------------------------------
 jud_id      | bigint                      | not null default nextval('judgements_id_seq'::regclass)
 rating      | character varying(255)      | 
 last_update | timestamp without time zone | 
 user_id     | character varying(255)      | 
 id          | integer                     | 
Indexes:
    "judgements_pkey" PRIMARY KEY, btree (jud_id)
Foreign-key constraints:
    "judgements_id_fkey" FOREIGN KEY (id) REFERENCES recommendations(id)
    "judgements_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(user_id)
Run Code Online (Sandbox Code Playgroud)

我在DB中有一个SEQUENCE名称'judgements_id_seq'

任何人都可以告诉我什么是错的??? 谢谢.

Cra*_*ger 82

Hibernate的PostgreSQL方言不是很明亮.它不知道你的每个SERIAL序列,并假设它可以使用一个名为"hibernate_sequence"的全局数据库范围的序列.


(更新:似乎更新的Hibernate版本可能会在GenerationType.IDENTITY指定时使用默认的每个表序列.测试你的版本并使用它而不是下面的代码如果它适用于你.)


您需要更改映射以明确指定每个序列.这很烦人,重复,毫无意义.

@Entity
@Table(name = "JUDGEMENTS")
public class Judgement implements Serializable, Cloneable {

    private static final long serialVersionUID = -7049957706738879274L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="judgements_id_seq")
    @SequenceGenerator(name="judgements_id_seq", sequenceName="judgements_id_seq", allocationSize=1)
    @Column(name = "JUD_ID")
    private Long _judId;
...
Run Code Online (Sandbox Code Playgroud)

allocationSize=1非常重要.如果省略它,Hibernate将盲目地假设序列是定义的,INCREMENT 50因此当它从序列中获取值时,它可以使用该值并将其下面的49个值作为唯一生成的键.如果您的数据库序列增加1(默认值),那么当Hibernate尝试重用现有密钥时,这将导致唯一的违规.

请注意,一次获得一个密钥导致每个插入一次额外的往返.据我所知,Hibernate无法INSERT ... RETURNING有效地返回生成的密钥,也无法使用JDBC生成的密钥接口.如果你告诉它使用一个序列,那么它将调用nextval以获得insert明确的值,从而导致两次往返.为了降低成本,可以在具有大量插入的键序列上设置更大的增量,记住在映射底层数据库序列上设置它.这将导致Hibernate nextval更频繁地调用并缓存密钥块,以便随时分发.

我相信你可以从上面看到我不同意这里做的Hibernate设计选择,至少从与PostgreSQL一起使用它的角度来看.他们应该使用getGeneratedKeys或使用INSERT ... RETURNINGDEFAULT为重点,让数据库照顾这个,而不必麻烦休眠其在序列或给他们明确的访问的名称自我.

顺便说一句,如果你正在使用Pg的Hibernate,你可能还需要一个用于Pg的oplock触发器,以允许Hibernate的乐观锁定与正常的数据库锁定安全地交互.没有它或类似的东西,你的Hibernate更新将倾向于破坏通过其他常规SQL客户端所做的更改.问我怎么知道.


小智 44

我似乎记得必须使用@GeneratedValue(strategy = GenerationType.IDENTITY)让Hibernate在PostgreSQL上使用'serial'列.


小智 12

您需要使用策略GenerationType.IDENTITY而不是GenerationType.AUTO设置@GeneratedId列

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JUD_ID")
private Long _judId;
Run Code Online (Sandbox Code Playgroud)

  • 是的,这种方法工作正常(特别是如果它是一个宠物项目),但是从性能的角度(在高负载应用程序中)使用它是不好的做法。Hibernate 需要为每个实体定义主键值。为了在 GenerationType.IDENTITY 的情况下检索它,Hibernate 必须立即执行插入语句。这种方法不允许 Hibernate 执行它的优化(例如将所有更改收集在一起并在单个查询中进行 - JDBC 批处理)。所以更好的解决方案是 GenerationType.SEQUENCE (2认同)

spl*_*dli 10

我以前遇到同样的错误,在你的数据库中输入这个查询 CREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;

这对我有用,祝你好运〜