Подтвердить что ты не робот

Hibernate не может получить следующее значение последовательности

У меня есть приложение gwt подключиться к 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

мой класс Judgment выглядит следующим образом

@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 'judments_id_seq' в DB

может кто-нибудь сказать мне, что случилось??? спасибо.

4b9b3361

Ответ 1

Диалог Hibernate PostgreSQL не очень яркий. Он не знает о ваших последовательностях в SERIAL и предполагает наличие глобальной последовательности в базе данных, называемой "hibernate_sequence", которую он может использовать.


(UPDATE). Похоже, что более новые версии 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, чтобы получить значение then insert, которое явно, что приведет к двум раундам. Чтобы снизить затраты на это, вы можете установить большее увеличение на последовательности клавиш с большим количеством вставок, не забывая установить его на карте и базовой последовательности базы данных. Это приведет к тому, что Hibernate вызовет nextval реже и блокирует кеш-ключи для раздачи по мере их появления.

Я уверен, что вы можете видеть из вышеизложенного, что я не согласен с выбором дизайна Hibernate, сделанным здесь, по крайней мере, с точки зрения использования его с PostgreSQL. Они должны использовать getGeneratedKeys или использовать INSERT ... RETURNING с DEFAULT для ключа, позволяя базе данных позаботиться об этом без спящего режима, чтобы беспокоиться о именах последовательностей или явного доступа к ним.

Кстати, если вы используете Hibernate с Pg, вам также понадобится триггер oplock для Pg, чтобы позволить оптимистичной блокировке Hibernate безопасно взаимодействовать с нормальной блокировкой базы данных, Без него или что-то вроде этого ваши обновления Hibernate будут иметь тенденцию к изменениям clobber, сделанным с помощью других обычных SQL-клиентов. Спросите меня, как я знаю.

Ответ 2

Кажется, мне кажется, что нужно использовать @GeneratedValue(strategy = GenerationType.IDENTITY), чтобы заставить Hibernate использовать столбцы "serial" на PostgreSQL.

Ответ 3

Вам нужно установить столбец @GeneratedId со стратегией GenerationType.IDENTITY вместо GenerationType.AUTO

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

Ответ 4

Я получил такую ​​же ошибку раньше, введите этот запрос в свою базу данных CREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;

которые работают для меня, удачи ~

Ответ 5

Я также хотел бы добавить несколько заметок о миграции MySQL-to-PostgreSQL:

  • В вашем DDL, в названии объекта предпочтительнее использовать символ "_" (подчеркивание) для разделения слов на случай верблюда. Последнее отлично работает в MySQL, но приносит много проблем в PostgreSQL.
  • Стратегия IDENTITY для аннотации @GeneratedValue в ваших полях идентичности класса модели отлично работает для PostgreSQLDialect в спящем режиме 3.2 и выше. Кроме того, стратегия AUTO является типичной настройкой для MySQLDialect.
  • Если вы комментируете свои классы моделей с помощью @Table и задаете буквальное значение, равное имени таблицы, убедитесь, что вы создали таблицы, которые будут храниться в общедоступной схеме.

Что, насколько я помню сейчас, надеюсь, что эти советы помогут вам немного минут проб и ошибок!

Ответ 6

Я думаю, что у вас уже есть достаточно ответа, но я получил точно такую ​​же ошибку, и моя проблема была другой. И я потратил немного времени на ее решение.

В моем случае проблема была владельцем последовательности в 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;

Я надеюсь, что это может быть полезно для всех.

Ответ 7

Использование GeneratedValue и GenericGenerator с native стратегией:

@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

База данных, которую мы используем, должна быть указана в поле search_path в файле конфигурации Postgres SQL. Это можно сделать, отредактировав файл конфигурации Postgressql, установив search_path вместе с именем базы данных, например: TESTDB.

  1. Найдите файл postgressql.conf в папке данных базы данных SQL Postgres.
  2. Set search_path = "$ user", public, TESTDB;
  3. Перезапустите службу Postgres SQL, чтобы изменения вступили в силу.

Это сработало для меня после внесения вышеуказанных изменений.

Ответ 9

При использовании Postgres создайте последовательность вручную с именем "hibernate_sequence". Это будет работать.

Ответ 10

Пожалуйста, используйте следующий запрос и измените вашу таблицу:   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")