52

我有 gwt 应用程序在后端连接到 postgres DB,并且有一个 java 类 'Judgement' 映射 DB 中的表 'judgements',当我试图将判断持久化到 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)

我在数据库中有一个 SEQUENCE 名称“judgements_id_seq”

谁能告诉我怎么了???谢谢。

4

11 回答 11

93

Hibernate 的 PostgreSQL 方言不是很亮。它不知道您的 per-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;
...

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

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

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

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

于 2012-05-17T01:00:47.747 回答
45

我似乎记得不得不使用@GeneratedValue(strategy = GenerationType.IDENTITY)让 Hibernate 在 PostgreSQL 上使用“串行”列。

于 2012-05-17T00:05:13.277 回答
13

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

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JUD_ID")
private Long _judId;
于 2015-10-01T00:54:19.387 回答
11

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

这对我有用,祝你好运~

于 2013-10-11T09:09:55.103 回答
2

我还想添加一些关于 MySQL 到 PostgreSQL 迁移的注释:

  1. 在您的 DDL 中,在对象命名中更喜欢使用“_”(下划线)字符来分隔单词,而不是骆驼大小写约定。后者在 MySQL 中运行良好,但在 PostgreSQL 中带来了很多问题。
  2. 模型类身份字段中@GeneratedValue 注释的 IDENTITY 策略适用于休眠 3.2 及更高版本中的 PostgreSQLDialect。此外,AUTO 策略是 MySQLDialect 的典型设置。
  3. 如果您使用 @Table 注释模型类并将文字值设置为等于表名的值,请确保您确实创建了要存储在公共模式下的表。

这就是我现在所记得的,希望这些技巧可以让你节省几分钟的试错时间!

于 2013-03-08T04:18:39.940 回答
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;

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

于 2013-06-19T16:01:35.083 回答
1

使用GeneratedValueand策略GenericGeneratornative

@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;
于 2018-06-28T21:41:42.780 回答
0

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

  1. 在 Postgres SQL 数据库的 data 文件夹下找到 postgressql.conf 文件。
  2. 设置 search_path = "$user", public, TESTDB;
  3. 重新启动 Postgres SQL 服务以影响更改。

进行上述更改后,它对我有用。

于 2018-01-02T12:17:32.143 回答
0

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

于 2019-05-28T11:34:06.950 回答
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")

于 2019-09-23T17:52:50.350 回答
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");
于 2019-11-04T21:31:47.220 回答