java PSQLException:错误:重复键值在使用 Hibernate 时违反了唯一约束

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36397008/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:23:37  来源:igfitidea点击:

PSQLException: ERROR: duplicate key value violates unique constraint when using Hibernate

javaspringhibernate

提问by Avi

I have two objects with one-to-many relationship between them that I implemented as follows:

我有两个对象,它们之间具有一对多的关系,我实现如下:

@Entity
@Table(name = "details")
public class MainDetails {
     @Id
     @Column(name = "details_id")
     @GeneratedValue(strategy= GenerationType.AUTO)
     private Long id;

     // Some other fields here - omitted

     @OneToMany(fetch = FetchType.LAZY,
                mappedBy = "details",
                targetEntity = State.class,
                cascade = CascadeType.ALL)
     @OrderBy("timestamp DESC")
     private List<State> states;
}

And the second one:

第二个:

@Entity
@Table(name = "state")
public class State {

     @Id
     @Column(name = "state_id")
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "details_id")
     private MainDetails details;

     // Other fields omitted (including timestamp)

}

I call a save()method on the MainDetailsobject. The method looks like this:

save()MainDetails对象上调用一个方法。该方法如下所示:

public T save(T obj) { // The T in this case is MainDetails
  entityManager.persist(obj);
  entityManager.flush();
  return obj;
}

But then I get this exception:

但后来我得到了这个例外:

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "details_pkey" Detail: Key (details_id)=(8) already exists.

My persistence.xmllooks like this:

我的persistence.xml看起来像这样:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
         version="2.0">
  <persistence-unit name="my-persistence-unit">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <!-- Annotated entity classes -->
    <class>com.company.entity.MainDetails</class>
    <class>com.company.entity.State</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect" />
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />
      <property name="hibernate.enable_lazy_load_no_trans" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

My spring context looks like this:

我的 spring 上下文如下所示:

@EnableJpaRepositories(basePackages = {"com.company.dao", "com.company.*.dao"})
@EnableTransactionManagement(proxyTargetClass = true)
@Import(BasicConfig.class)
public class DbConfig {

  @Value("${db.connection_string}")
  private String connectionString;

  @Value("${db.user_name}")
  private String dbUserName;

  @Value("${db.password}")
  private String dbPassword;

  @Bean
  public DataSource dataSource() {
    DriverManagerDataSource driver = new DriverManagerDataSource();
    driver.setDriverClassName("org.postgresql.Driver");
    driver.setUrl(connectionString);
    driver.setUsername(dbUserName);
    driver.setPassword(dbPassword);
    return driver;
  }

  @Bean
  public JpaVendorAdapter jpaVendorAdapter() {
    HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    adapter.setShowSql(true);
    adapter.setGenerateDdl(true);
    adapter.setDatabase(Database.POSTGRESQL);
    return adapter;
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {
    LocalContainerEntityManagerFactoryBean factoryBean = new  LocalContainerEntityManagerFactoryBean();
    factoryBean.setDataSource(dataSource());
    factoryBean.setPersistenceUnitName("my-persistence-unit");
    factoryBean.setJpaVendorAdapter(jpaVendorAdapter());

    return factoryBean;
  }

  @Bean
  public JpaTransactionManager transactionManager() throws ClassNotFoundException {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());

    return transactionManager;
  }
}

回答by Avi

Ok, that was my mistake (naturally) and I changed 3 things in order for it to work:

好吧,那是我的错误(自然地),我改变了 3 件事以使其正常工作:

  1. Changed both classes to have: @GeneratedValue(strategy= GenerationType.TABLE)(Originally I used GenerationType.AUTO).

  2. I figured out that the method that calls save()also calls entityManager.flush(). After removing the redundant line it solved the issue. Beats me why - I would expect hibernate to just do nothing on a redundant flush()call, but apparently it was a must in order to solve the issue.

  1. 将两个类都更改为:(@GeneratedValue(strategy= GenerationType.TABLE)最初我使用GenerationType.AUTO)。

  2. 我发现调用的方法save()也调用entityManager.flush(). 去掉多余的线后,问题就解决了。打败我的原因 - 我希望 hibernate 在冗余flush()调用中什么都不做,但显然这是解决问题的必要条件。