【问题标题】:Springboot + Hibernate: Duplicate entry Exception while save entitySpringboot + Hibernate:保存实体时出现重复条目​​异常
【发布时间】:2020-07-22 13:26:44
【问题描述】:

我有 2 个简单的实体:

@Entity
@Table(name = "user")
public class User extends Base {

   private String firstname;
   private String lastname;

   @OneToMany
   @JoinTable(
        name="user_emails",
        joinColumns = @JoinColumn( name="user_id"),
        inverseJoinColumns = @JoinColumn( name="email_id")
   )
   private List<Email> emails = new ArrayList<>();

   // getter setter
}

和电子邮件(没有任何关于用户的参考)

@Entity
@Table(name = "email")
public class Email extends Base {

    private String sender;

    private String receiver;
}

第一封邮件一切正常 但现在我想使用以下代码向用户保存第二封电子邮件(引发错误)。问题是,它们是“saveUser-line”处的 2 封邮件,我认为 hibernate 尝试再次保存第一个邮件并获得重复条目异常。我该怎么做?重要的是要知道:还有其他对象,例如用户,它们都尝试保存电子邮件(也不起作用)。

    // Create Email object
    eMailRepository.save(email);


    if (user != null) {
        user.getEmails().add(email);
        userDatabaseRepository.save(user); // ERROR THROWN
    }

这里是创建的实体表

这里是问题sql:

Hibernate: insert into user_emails (user_id, email_id) values (?, ?)

这里有一个例外:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'databaseSeedConfig' defined in file [E:\Arbeit\---\target\classes\de\---\config\DatabaseSeedConfig.class]: Invocation of init method failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_1j6q2cqg40ooyo8m7kq2miws2]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
    at de.dev.Pfffff.main(Pfffff.java:10)
Caused by: org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_1j6q2cqg40ooyo8m7kq2miws2]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:296)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:534)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy134.save(Unknown Source)
    at de.dev.service.EMailQueueService.addEMailToQueue(EMailQueueService.java:132)
    at de.dev.service.EMailQueueService.addEMailToQueue(EMailQueueService.java:91)
    at de.dev.service.UserService.addUser(UserService.java:173)
    at de.dev.config.DatabaseSeedConfig.setUpAdminUser(DatabaseSeedConfig.java:133)
    at de.dev.config.DatabaseSeedConfig.afterPropertiesSet(DatabaseSeedConfig.java:99)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
    ... 16 common frames omitted
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1340)
    at org.hibernate.action.internal.CollectionUpdateAction.execute(CollectionUpdateAction.java:83)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3290)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2486)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:532)
    ... 39 common frames omitted
Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '2' for key 'UK_1j6q2cqg40ooyo8m7kq2miws2'
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:955)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1094)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1042)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1345)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1027)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
    ... 56 common frames omitted

【问题讨论】:

  • 你能分享一下异常吗?同时打开 show_sql 标志以查看插入语句
  • 当然,我做到了:)
  • 你能用 Set 代替 List 来发送邮件吗?您将避免重复
  • 然后休眠实体表中的两个 PK(user_id,email_id),因此我无法为一个用户添加两个条目(2 封邮件)。
  • 当您为 Set 元素调用 addEmail 时,不会添加,您将避免重复。另外你为什么使用 JoinTable 而不是 JoinColumn?

标签: java spring hibernate join duplicates


【解决方案1】:

当您第二次调用它时,userDatabaseRepository.saveOrUpdate(user); 而不是 userDatabaseRepository.save(user); 不会帮助您吗?

【讨论】:

  • 我没有“saveOrUpdate”方法
  • 您的存储库扩展了什么接口?
【解决方案2】:

试试这样的

电子邮件.java

@Entity
@Table(name = "user")
@Getter
@Setter
public class User extends Base {

   private String firstname;
   private String lastname;

   @OneToMany
   @JoinTable(
        name="user_emails",
        joinColumns = @JoinColumn( name="user_id"),
        inverseJoinColumns = @JoinColumn( name="email_id")
   )
   private List<Email> emails = new ArrayList<>();

   private void addEmail(Email email){
      emails.add(email);
   }

   private void removeEmail(Email email){
      emails.remove(email);
   }
}

UserRepository.java

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

  User findByNameAndSurname(String name, String surname);

}

EmailRepository.java

@Repository
public interface EmailRepository extends JpaRepository<Email, Long> {

   Email findBySenderAndReceiver(String sender, String receiver);

}

SomeClass.java


@Autowired
private EmailRepository emailRepository;
@Autowired
private UserRepository userRepository;

/*
Some code
*/

emailRepository.saveAndFlush(email);

Email email = emailRepository.findBySenderAndReceiver("Sender", "Receiver");
emailRepository.flush();

User user = userRepository.findByNameAndSurname("Carlos", "Matos");

if(user != null){
 user.addEmail(email);
 userRepository.saveAndFlush(user);
}

【讨论】:

  • 如果 User#addEmail() 是私有的,这如何工作?
猜你喜欢
  • 2011-10-28
  • 2021-10-17
  • 2019-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
  • 1970-01-01
相关资源
最近更新 更多