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