hibernate无法获得下一个序列值

时间:2012-05-16 23:28:49

标签: hibernate postgresql

我有gwt应用程序连接到后端的postgres DB,以及一个java类'Judgment'映射数据库中的表'判断',当我试图将判断持久化到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

我的审判类看起来像这样

@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;
...

我的表判断是:

   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)

我在DB

中有一个SEQUENCE名称'judgements_id_seq'

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

11 个答案:

答案 0 :(得分:80)

Hibernate的PostgreSQL方言不是很明亮。它不知道你的每个SERIAL序列,并假设有一个全局数据库范围的序列叫做“hibernate_sequence”它可以使用。


UPDATE :在指定GenerationType.IDENTITY时,似乎较新的Hibernate版本可能会使用默认的每表序列。如果适用,请测试您的版本并使用此版本代替以下版本你。)


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

@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;
...

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

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

我相信你可以从上面看到我不同意这里所做的Hibernate设计选择,至少从与PostgreSQL一起使用它的角度来看。他们应该使用getGeneratedKeys或使用INSERT ... RETURNINGDEFAULT作为密钥,让数据库处理这个问题,而Hibernate不必在序列名称或显式访问权限上自行解决问题。它们。

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

答案 1 :(得分:41)

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

答案 2 :(得分:11)

您需要使用策略GenerationType.IDENTITY而不是GenerationType.AUTO

设置@GeneratedId列
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JUD_ID")
private Long _judId;

答案 3 :(得分:8)

我之前有同样的错误, 在数据库CREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;

中键入此查询

这对我有用,祝你好运〜

答案 4 :(得分:2)

我还想补充一些关于MySQL-to-PostgreSQL迁移的注释:

  1. 在您的DDL中,在对象命名中,更喜欢使用'_'(下划线)字符进行单词分离,使其符合驼峰惯例。后者在MySQL中运行良好但在PostgreSQL中带来了很多问题。
  2. 模型类标识字段中@GeneratedValue注释的IDENTITY策略适用于hibernate 3.2及更高版本中的PostgreSQLDialect。此外,AUTO策略是MySQLDialect的典型设置。
  3. 如果使用@Table注释模型类并将其设置为等于表名的文字值,请确保创建了要存储在公共模式下的表。
  4. 就我现在所记得的那样,希望这些技巧可以让你免费试听几分钟的试错!

答案 5 :(得分:2)

我认为你已经有了足够的答案,但我得到了完全相同的错误,我的问题是另一个错误。我浪费了一点时间试图解决它。

在我的情况下,问题是Postgres中序列的所有者。因此,如果上述任何解决方案都没有解决您的问题,请检查序列的所有者是否应该拥有权限的用户/角色。

关注示例:

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

ALTER TABLE public.seq_abcd OWNER TO USER_APP;

我希望它对任何人都有用。

答案 6 :(得分:0)

我们正在使用的数据库应该在Postgres SQL配置文件的search_path下提及。这可以通过设置search_path和数据库名称来编辑Postgressql配置文件来完成,例如:TESTDB。

  1. 在Postgres SQL数据库的数据文件夹下找到postgressql.conf文件。
  2. 设置search_path =" $ user",public,TESTDB;
  3. 重新启动Postgres SQL服务以影响更改。
  4. 在做出上述改变后,它对我有用。

答案 7 :(得分:0)

GeneratedValueGenericGeneratornative策略结合使用:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_native")
@GenericGenerator(name = "id_native", strategy = "native")
@Column(name = "id", updatable = false, nullable = false)
private Long id;

我必须创建一个序列调用hibernate_sequence,因为Hibernate默认会查找这样的序列:

create sequence hibernate_sequence start with 1 increment by 50;
grant usage, select on all sequences in schema public to my_user_name;

答案 8 :(得分:0)

如果使用Postgres,请使用名称“ hibernate_sequence”手动创建序列。它将起作用。

答案 9 :(得分:0)

请使用以下查询并更改您的表:     CREATE SEQUENCE user_id_seq START 1; ALTER TABLE product.users ALTER COLUMN user_id SET DEFAULT nextval('user_id_seq'); ALTER SEQUENCE users.user_id_seq OWNED BY users.user_id;

并在您的实体类中使用this

@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="user_id_seq")

答案 10 :(得分:0)

对于使用FluentNHibernate(我的版本是2.1.2)的任何人来说,它都是重复的,但这是可行的:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Table("users");
        Id(x => x.Id).Column("id").GeneratedBy.SequenceIdentity("users_id_seq");