Генерация уникального id Hibernate Java

89
12 июня 2021, 17:00

Есть таблица в БД PostgreSql. У этой таблицы есть ограничение на уникальность для id. Сохраняю сущности в БД посредством Hibernate.

Код Entity:

@Entity
@Table(name = "cinema_movie")
public class Cinema_Movie {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "cinema_id")
    private String cinemaId;
    @Column(name = "movie_id")
    private String movieId;

Геттеры и сеттеры, плюс конструктор прилагаются. Не писал для сокращения кода.

Код сохранения в БД:

public void save() {
        CinemaMovie cinema_movie = new CinameMovie();
        cinema_movie.setCinemaId("random");
        cinema_movie.setMovieId("random")
        session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        session.save(cinema_movie); 
    }

Ну и в HibernateSessionFactoryUtil ничего особенного нет:

public static SessionFactory getSessionFactory() {
        logger.debug("Start method getSessionFactory() at HibernateSessionFactoryUtil.class");
        if (sessionFactory == null) {
            try {
                Configuration configuration = new Configuration().configure();
                configuration.addAnnotatedClass(Cinema_Movie.class);
                StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
                sessionFactory = configuration.buildSessionFactory(builder.build());
            } catch (Exception e) {
                logger.error("Error at method getSessionFactory() at HibernateSessionFactoryUtil.class: ", e);
            }
        }
        logger.debug("End of method getSessionFactory() at HibernateSessionFactoryUtil.class");
        return sessionFactory;
    }

И соответственно, метод save() вызывается переодически в разное время в программе. Изменения в БД в данную таблицу вносились руками, удалялись некоторые записи, т.к. программа только на стадии разработки.

Вопрос в следующем:

Как происходит генерация уникальных значений в Hibernate, и почему переодически я получаю ошибку:

ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности

?

А так же, как избежать данной ошибки, т.е. чтобы Hibernate точно гененрировал уникальные ID, которых еще нет в БД? Только дополнительной проверкой? Или сделать другой primary key, который самому генерировать? Или же есть какая то возможность исключения такой ошибки с помощью инструментов Hibernate?

Answer 1

Оригинал ответа можно найти тут.

В Hibernate есть возможность создания кастомных ID.

Вот примитивный вариант её реализации:

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "player_generator")
    @SequenceGenerator(name="player_generator", sequenceName = "player_seq", allocationSize = 1, initialValue = 1)
    private Long id;

Итак:
generator = "player_generator" - Это названия генератора, который будем использовать (название может быть любое. Главное в кавычках =) )
name="player_generator" - Название кастомного генератора
sequenceName = "player_seq" - это под каким названием будет создана таблица в базе данных
allocationSize = 1 (Optional. Можно не писать) - Это на сколько будет увеличиваться ваш id. [По дефолту - на 50]
initialValue = 1 (Optional. Можно не писать) - Это с какого числа начинается отсчет. [По дефолту - с 1]

Также на данном сайте рассказываются про разные стратегии:

  • Auto
  • Sequence
  • identity
Answer 2

Можете использовать стратегию increment. Она очень неэффективная, но должна решить вашу проблему (хотя бы на время разработки). При этом каждый раз при вставке сущности будет происходить обращение к базе для чтения последнего id. Для настройки надо определить генератор id.

@Entity
@Table(name = "cinema_movie")
public class Cinema_Movie {
    @Id
    @GeneratedValue(generator = "ID_GENERATOR")
    private int id;

Так как он может использоваться сразу в нескольких сущностях, определим его на уровне пакета. Создадим файл package-info.java в пакете с сущностями:

package-info.java

@org.hibernate.annotations.GenericGenerator(
        name = "ID_GENERATOR",
        strategy = "increment",
        parameters = {
                @org.hibernate.annotations.Parameter(
                        name = "sequence_name",
                        value = "MY_SEQUENCE"
                )
        }
)
package com.project.entities; // имя пакета
READ ALSO
Почему событие срабатывает только для последнего элемента? [дубликат]

Почему событие срабатывает только для последнего элемента? [дубликат]

Есть массив объявлений, к каждому из которых генерируется метка на карте и карточка к нейПри клике на метку, должна отобразиться соответствующая...

70
Как сохранить место прокрутки страницы после перезагрузки?

Как сохранить место прокрутки страницы после перезагрузки?

Я пользуюсь VS Code и там же запускаю localhost для авто перезагрузки страницы (после сохранения файла)Но проблема в том, что после этой перезагрузки...

78
Как вызвать методы компонента VueJs

Как вызвать методы компонента VueJs

Создаю компонент диалога

101
Алгоритм поиска подстроки в массиве строк (Javascript)

Алгоритм поиска подстроки в массиве строк (Javascript)

Необходимо реализовать алгоритм проверяющий наличие подстроки в массиве строк и возвращающая номера элементов массива, в которых встретилась...

82