Hibernate ошибка повторяющееся значение ключа нарушает ограничение уникальности

Есть таблица в БД 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?

I have the following problem

@Entity
@Table(name="tb_pessoa", schema="public")
@Inheritance(strategy = InheritanceType.JOINED)
public class Pessoa implements Serializable {
   private static final long serialVersionUID = 1L;

   @Id
   @SequenceGenerator(name = "tb_pessoa_id_seq", sequenceName = "tb_pessoa_id_seq", schema="public")
   @GeneratedValue(strategy = GenerationType.AUTO, generator = "tb_pessoa_id_seq")
   @Column(name = "id", nullable = false)
   private Integer id;

   ...

@Entity  
@Table(name="tb_pessoafisica", schema="public")
@PessoaFisicaAnnotation
@PrimaryKeyJoinColumn(name = "id")
public class PessoaFisica extends Pessoa implements Serializable {
   private static final long serialVersionUID = 1L;

   @Column(name = "email")
   private String email;

   ...

Assuming the Pessoa table has records with id 1 to 500. When I run the code below:

PessoaFisica pessoaFisica = new PessoaFisica();
pessoaFisica.setEmail("teste@123.com");

...

em.persist(pessoa);

It’s happening the following error:

17:26:13,613 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--10.36.1.49-8180-1) ERROR: duplicate key value violates unique constraint "tb_pessoa_pkey"
    Detalhe: Key (id)=(438) already exists.
17:26:13,614 WARN  [com.arjuna.ats.arjuna] (http--10.36.1.49-8180-1) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffff7f000101:-7f6ae4e3:558080ed:4f, org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization@331af73a >: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: duplicate key value violates unique constraint "tb_pessoa_pkey"
  Detalhe: Key (id)=(438) already exists.

why is trying to use the id 438 and not 501???

Does anyone know what might be happening?

thank you very much

CREATE TABLE tb_pessoa
(
    id integer NOT NULL,
    CONSTRAINT tb_pessoa_pkey PRIMARY KEY (id)
)

CREATE TABLE tb_pessoafisica
(
    email character varying(64) NOT NULL,
    CONSTRAINT tb_pessoafisica_pkey PRIMARY KEY (id),
    CONSTRAINT fkee8c050f70415778 FOREIGN KEY (id)
        REFERENCES tb_pessoa (id) MATCH SIMPLE
)

CREATE SEQUENCE tb_pessoa_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 500
  CACHE 1;

Log Hibernate:

07:50:52,463 INFO  [stdout] (http--10.36.1.49-8180-2) Hibernate: 
07:50:52,463 INFO  [stdout] (http--10.36.1.49-8180-2)     select
07:50:52,464 INFO  [stdout] (http--10.36.1.49-8180-2)         nextval ('public.tb_pessoa_id_seq')
07:50:52,497 INFO  [stdout] (http--10.36.1.49-8180-2) Hibernate: 
07:50:52,498 INFO  [stdout] (http--10.36.1.49-8180-2)     insert 
07:50:52,499 INFO  [stdout] (http--10.36.1.49-8180-2)     into
07:50:52,499 INFO  [stdout] (http--10.36.1.49-8180-2)         public.tb_pessoa
07:50:52,500 INFO  [stdout] (http--10.36.1.49-8180-2)         (id) 
07:50:52,500 INFO  [stdout] (http--10.36.1.49-8180-2)     values
07:50:52,501 INFO  [stdout] (http--10.36.1.49-8180-2)         (?)
07:50:52,519 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--10.36.1.49-8180-2) SQL Error: 0, SQLState: 23505
07:50:52,521 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--10.36.1.49-8180-2) ERROR: duplicate key value violates unique constraint "tb_pessoa_pkey"
    Detalhe: Key (id)=(438) already exists.

Есть три сущности
Город и Источник погоды ( они идентичны ):

public class City {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(unique = true, nullable = false)
    private String cityName;

    public City(String cityName) {
        this.cityName = cityName;
    }
}

Погода:

public class Weather {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private LocalDateTime date;
    private double temp;
    private double humidity;
    private int pressure;
    private String weatherDescription;

    @ManyToOne
    @JoinColumn(name="weather_source_id")
    private WeatherSource weatherSource;

    @ManyToOne
    @JoinColumn(name="city_id")
    private City city;
}

При добавлении погоды с городом, который уже есть в городе получаем ошибку:

//выше получена погода
        w.setCity(new City("Rostov-on-Don"));
        w.setWeatherSource(new WeatherSource("openWeather"));
        weatherService.add(w);

ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности «uk_djnk44fptegbsu6drhc9xvlfj»

Подробности: Ключ «(city_name)=(Rostov-on-Don)» уже существует.
Как сделать, чтобы hibernate не пытался добавить запись в таблицу городов, если там уже есть нужный город?
Пробовал использовать в equals и hasCode только значение name. Неужели перед тем как добавить нужно просто из сервиса вытянуть город по имени и его уже добавлять к погоде? нельзя ли это сделать автоматически?

Есть таблица в БД 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?

I have the following problem

@Entity
@Table(name="tb_pessoa", schema="public")
@Inheritance(strategy = InheritanceType.JOINED)
public class Pessoa implements Serializable {
   private static final long serialVersionUID = 1L;

   @Id
   @SequenceGenerator(name = "tb_pessoa_id_seq", sequenceName = "tb_pessoa_id_seq", schema="public")
   @GeneratedValue(strategy = GenerationType.AUTO, generator = "tb_pessoa_id_seq")
   @Column(name = "id", nullable = false)
   private Integer id;

   ...

@Entity  
@Table(name="tb_pessoafisica", schema="public")
@PessoaFisicaAnnotation
@PrimaryKeyJoinColumn(name = "id")
public class PessoaFisica extends Pessoa implements Serializable {
   private static final long serialVersionUID = 1L;

   @Column(name = "email")
   private String email;

   ...

Assuming the Pessoa table has records with id 1 to 500. When I run the code below:

PessoaFisica pessoaFisica = new PessoaFisica();
pessoaFisica.setEmail("teste@123.com");

...

em.persist(pessoa);

It’s happening the following error:

17:26:13,613 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--10.36.1.49-8180-1) ERROR: duplicate key value violates unique constraint "tb_pessoa_pkey"
    Detalhe: Key (id)=(438) already exists.
17:26:13,614 WARN  [com.arjuna.ats.arjuna] (http--10.36.1.49-8180-1) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffff7f000101:-7f6ae4e3:558080ed:4f, org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization@331af73a >: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: duplicate key value violates unique constraint "tb_pessoa_pkey"
  Detalhe: Key (id)=(438) already exists.

why is trying to use the id 438 and not 501???

Does anyone know what might be happening?

thank you very much

CREATE TABLE tb_pessoa
(
    id integer NOT NULL,
    CONSTRAINT tb_pessoa_pkey PRIMARY KEY (id)
)

CREATE TABLE tb_pessoafisica
(
    email character varying(64) NOT NULL,
    CONSTRAINT tb_pessoafisica_pkey PRIMARY KEY (id),
    CONSTRAINT fkee8c050f70415778 FOREIGN KEY (id)
        REFERENCES tb_pessoa (id) MATCH SIMPLE
)

CREATE SEQUENCE tb_pessoa_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 500
  CACHE 1;

Log Hibernate:

07:50:52,463 INFO  [stdout] (http--10.36.1.49-8180-2) Hibernate: 
07:50:52,463 INFO  [stdout] (http--10.36.1.49-8180-2)     select
07:50:52,464 INFO  [stdout] (http--10.36.1.49-8180-2)         nextval ('public.tb_pessoa_id_seq')
07:50:52,497 INFO  [stdout] (http--10.36.1.49-8180-2) Hibernate: 
07:50:52,498 INFO  [stdout] (http--10.36.1.49-8180-2)     insert 
07:50:52,499 INFO  [stdout] (http--10.36.1.49-8180-2)     into
07:50:52,499 INFO  [stdout] (http--10.36.1.49-8180-2)         public.tb_pessoa
07:50:52,500 INFO  [stdout] (http--10.36.1.49-8180-2)         (id) 
07:50:52,500 INFO  [stdout] (http--10.36.1.49-8180-2)     values
07:50:52,501 INFO  [stdout] (http--10.36.1.49-8180-2)         (?)
07:50:52,519 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--10.36.1.49-8180-2) SQL Error: 0, SQLState: 23505
07:50:52,521 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--10.36.1.49-8180-2) ERROR: duplicate key value violates unique constraint "tb_pessoa_pkey"
    Detalhe: Key (id)=(438) already exists.

Есть три сущности
Город и Источник погоды ( они идентичны ):

public class City {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(unique = true, nullable = false)
    private String cityName;

    public City(String cityName) {
        this.cityName = cityName;
    }
}

Погода:

public class Weather {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private LocalDateTime date;
    private double temp;
    private double humidity;
    private int pressure;
    private String weatherDescription;

    @ManyToOne
    @JoinColumn(name="weather_source_id")
    private WeatherSource weatherSource;

    @ManyToOne
    @JoinColumn(name="city_id")
    private City city;
}

При добавлении погоды с городом, который уже есть в городе получаем ошибку:

//выше получена погода
        w.setCity(new City("Rostov-on-Don"));
        w.setWeatherSource(new WeatherSource("openWeather"));
        weatherService.add(w);

ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности «uk_djnk44fptegbsu6drhc9xvlfj»

Подробности: Ключ «(city_name)=(Rostov-on-Don)» уже существует.
Как сделать, чтобы hibernate не пытался добавить запись в таблицу городов, если там уже есть нужный город?
Пробовал использовать в equals и hasCode только значение name. Неужели перед тем как добавить нужно просто из сервиса вытянуть город по имени и его уже добавлять к погоде? нельзя ли это сделать автоматически?

#java #postgresql #hibernate #spring-boot #jpa

#java #postgresql #впасть в спящий режим #пружинный ботинок #jpa

Вопрос:

Повторяющееся значение ключа нарушает ограничение уникальности после сохранения объекта @ManyToOne

Я попытался сохранить объект A, у которого есть другой объект B с уникальным именем поля с помощью spring-data. Если B уже существует в БД, то будет выдано исключение «дублирующее значение ключа нарушает уникальное ограничение «b_name_key». Подробно: Ключ (b_name)=(someName) уже существует.

 create table b
(
  b_id         serial primary key,
  b_name varchar(3) not null unique
);

create table a
(
  a_id            serial primary key,
  b_id      int references b (b_id) not null,
);


@Entity
@Getter
@Setter
public class B implements java.io.Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long b_id;
    @Column(name = "b_name", unique = true)
    private String bName;

    public B(String bName) {
        this.bName = bName;
    }

    public B() {}

    @Override
    public String toString() {
        return "...";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        B b = (B) o;
        return Objects.equals(bName, b.bName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(bName);
    }
}

@Entity
@Getter
@Setter
public class a implements java.io.Serializable{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long a_id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "b_id")
    private B b;


    public a() {
    }

    public a(B b  ) {
        this.b = b;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        a a = (a) o;
        return Objects.equals(b, a.b)
    }

    @Override
    public int hashCode() {
        return Objects.hash(b);
    }
}


@Repository
public interface ARepository extends JpaRepository<Metastasis, Long> {}

@Controller
public class AController {

    private final ARepository aRepository;

    public AController(ARepository aRepository) {
        this.aRepository = aRepository;
    }

    @GetMapping("/test")
    public String showaddUserForm() {
        B b = new B("SomeName");
        A a = new A(b);
        aRepository.save(a);
        return "index";
    }
}

@SpringBootApplication
@EnableJpaRepositories(basePackages = "...repositories")
@EnableTransactionManagement
@EntityScan(basePackages = "....entities")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
 

Я получаю org.postgresql.util.PSQLException: ОШИБКА: повторяющееся значение ключа нарушает уникальное ограничение «b_name_key»
Подробно: ключ (b_name) = (SomeName) уже существует.

Ответ №1:

Это нормально. Поскольку a объект является новым, операция сохранения будет каскадно передана b объекту, который также является новым, и завершится неудачей, поскольку в базе данных уже есть запись с этим ключом.

Попробуйте что-то вроде:

 // find for B
B b = bRepository.findById(..);
// if not found, create one
if (b == null) {
   b = new B("SomeName");
} 
A a = new A(b);
aRepository.save(a);
 

Комментарии:

1. Почему спящий режим не может справиться с этим сам?

Есть таблица в БД 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?

При переходе с Hibernate 4 на 5.3.1 (Wildfly 14.0.1) я также столкнулся с проблемой, связанной с сообщением об ошибке «повторяющееся значение ключа нарушает уникальное ограничение»hibernate_sequences_pkey. После изучения исходного кода Hibernate 5.3.1 я смог избавиться ошибки с помощью strategy = GenerationType.TABLE(Я также знаю, что эта стратегия не идеальное решение). Основная проблема была в классе TableGenerator. Для решения проблемы следует дополнительно использовать аннотацию GenericGenerator, например:

@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = TableGenerator.DEF_TABLE)
@GenericGenerator(name = TableGenerator.DEF_TABLE, strategy
        = "org.hibernate.id.enhanced.TableGenerator", parameters = {
        @Parameter(name = TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, value = "true")})
@Column(name="id")
private Integer id;

установка TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITYзначение true (так как по умолчанию он имеет значение false, и в этом случае Hibernate будет использовать имя сегмента «по умолчанию» в таблице hibernate_sequences вместо имен таблиц). Вы также должны установитьhibernate.model.generator_name_as_sequence_nameзначение false, чтобы иметь только одну таблицу hibernate_sequences, иначе Hibernate будет использовать имена генераторов в качестве имен для таблиц последовательностей (согласно https://github.com/hibernate/hibernate-orm/commit/9a75fa8d979185b6014a814bf3ffd09e32143939). Дополнительно (но не обязательно) вы можете установитьhibernate.id.generator.stored_last_usedсвойство также на ложное значение (https://github.com/hibernate/hibernate-orm/commit/9af565510064635dba7e48087ab4e8f5ef439f0d изменяется), потому что:

Чтобы соответствовать спецификациям JPA, значение, сохраненное Hibernate 5.3 в таблице, используемой
javax.persistence.TableGeneratorэто последнее созданное значение. Предыдущие версии Hibernate вместо этого сохраняли следующее значение, которое будет использоваться.

Для обратной совместимости новый параметр,
hibernate.id.generator.stored_last_used, была представлена ​​возможность вернуться к старому поведению Hibernate. Существующие приложения, переходящие на версию 5.3 и использующие @TableGenerator, должны установитьhibernate.id.generator.stored_last_used к false

Понравилась статья? Поделить с друзьями:
  • Heroes of the storm непредусмотренная фатальная ошибка
  • Hiberfil sys ошибка при загрузке
  • Hikvision ошибка 102009
  • Heroes of might and magic 6 ошибка 0xc0000906
  • Hikvision код ошибки 8200