【问题标题】:hibernate could not get next sequence value休眠无法获得下一个序列值
【发布时间】:2012-05-24 13:55:13
【问题描述】:

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

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”

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

【问题讨论】:

    标签: hibernate postgresql


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      请使用以下查询并更改您的表格: 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")

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

          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;
          

          【讨论】:

            【解决方案5】:

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

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

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

            【讨论】:

              【解决方案6】:

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

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

              【讨论】:

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

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

              【讨论】:

              • 谢谢,我没有使用策略属性,这就是为什么会出错。
              【解决方案8】:

              Hibernate 的 PostgreSQL 方言不是很亮。它不知道您的 per-SERIAL 序列,并假设它可以使用一个名为“hibernate_sequence”的全局数据库范围序列。


              (更新:当指定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 不必为序列名称或显式访问它们而烦恼。

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

              【讨论】:

              • 你愿意帮我解决类似的问题吗?这是链接:stackoverflow.com/questions/25252541/…
              • @Craig Ringer 我已经通过添加 appocationSize = 1 解决了这个问题,但这是正确的方法吗?
              • @GeneratedValue(strategy = GenerationType.IDENTITY) 为我使用 Spring Data JPA、PostgreSQL 9.5 和 v 9.4 的 JDBC 驱动程序。
              • @TomaszWaszczyk-PantaRhei 是的,allocationSize = 1 是典型的,如果您从 PostgreSQL 创建序列,因为 PostgreSQL 期望它们一次推进一个,但大多数 JPA 实现假设它们将在块中推进50 个。
              【解决方案9】:

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

              这对我有用,祝你好运~

              【讨论】:

              • 如果我们有多个需要使用的序列,这并不能真正解决问题
              • 至少对于 Postgres,这是“NO CYCLE”而不是“NOCYCLE”
              【解决方案10】:

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

              在我的情况下,问题是 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;
              

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

              【讨论】:

                【解决方案11】:

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

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

                就我现在所记得的,希望这些提示可以让您节省几分钟的试错时间!

                【讨论】:

                • FWIW,混合大小写很好。你只需要“双引号”来保存大小写。这实际上是 SQL 标准行为,MySQL 只是忽略它。
                猜你喜欢
                • 2011-09-28
                • 2011-08-09
                • 1970-01-01
                • 2011-09-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-01-08
                相关资源
                最近更新 更多