2017-04-18 56 views
0

我有一個使用hibernate 5.2和JPA來處理數據庫的spring服務器。JPA合併拋出異常在刷新期間重複鍵'PRIMARY'的條目

我們有一個過程,收集大量數據並保存基於該數據的事件。它每天都在運行,這些事件可能會改變價值。有時,當我嘗試保存這些內容時,出現以下情況:

15:28:32.819 [pool-6-thread-3] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Duplicate entry 'VAL-below_avg-2017-04-07' for key 'PRIMARY' 
Query is: insert into event_date (description, period, time, date, symbol, type) values (?, ?, ?, ?, ?, ?, ?) 
Query is: 
insert into event_date (description, period, time, date, symbol, type) values (?, ?, ?, ?, ?, ?, ?) 
[org.hibernate.exception.ConstraintViolationException: could not execute statement] 
15:28:32.822 [pool-6-thread-3] ERROR org.hibernate.internal.ExceptionMapperStandardImpl - HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement] 
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:278) 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) 
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) 

我們在這裏沒有做任何事情。我們處理數據。我們創建新的對象。我們將它們傳遞到下面的方法在我們的DAO:

public void saveOrUpdate(List<EventDate> events) { 
    for (EventDate e : events) { 
     try{ 
      entityManager.merge(e); 
     }catch(Exception e1){ 
      logger.error("Something broke!"); 
     } 
    } 
} 

我已經通過大約十幾個類似的問題了,但在所有這些,這個問題似乎被某種與另一對象定向關係引起的。就我而言,沒有這樣的事情。我也看到一些人認爲這是一個沒有hashcode和equals的問題,所以我實現了這些無濟於事。

我的實體類如下所示(有繼承EVENTDATE許多實體,但他們大多隻是在這裏添加一些元屬性和在那裏,我不認爲問題在於他們:

@Entity 
@Table(name = "event_date") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="type", discriminatorType=DiscriminatorType.STRING, length=255) 
@DiscriminatorOptions(insert=false) 
@JsonIgnoreProperties(ignoreUnknown=true) 
public abstract class EventDate implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @EmbeddedId 
    private SymDateTypeId id; 

    @Column(columnDefinition=COLUMN_DATETIME) 
    private String time = "UNKNOWN"; 

    @Column(columnDefinition=COLUMN_TEXT) 
    private String description; 

    @Column(columnDefinition=COLUMN_VARCHAR20) 
    private String period; 

    //Getters/Setters/Hashcode/Equals omitted... 
} 

@Embeddable 
public class SymDateTypeId implements Serializable{ 
    private static final long serialVersionUID = 1L; 

    @Column(nullable=false) 
    private String symbol = "UNKNOWN"; 
    @Column(nullable=false) 
    private String date = "UNKNOWN"; 
    @Column(nullable=false) 
    private String type; 

    //Getters and setters omitted... 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + ((date == null) ? 0 : date.hashCode()); 
     result = prime * result + ((symbol == null) ? 0 : symbol.hashCode()); 
     result = prime * result + ((type == null) ? 0 : type.hashCode()); 
     return result; 
    } 
    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     SymDateTypeId other = (SymDateTypeId) obj; 
     if (date == null) { 
      if (other.date != null) 
       return false; 
     } else if (!date.equals(other.date)) 
      return false; 
     if (symbol == null) { 
      if (other.symbol != null) 
       return false; 
     } else if (!symbol.equals(other.symbol)) 
      return false; 
     if (type == null) { 
      if (other.type != null) 
       return false; 
     } else if (!type.equals(other.type)) 
      return false; 
     return true; 
    } 
} 

回答

1
Duplicate entry 'VAL-below_avg-2017-04-07' for key 'PRIMARY' 

明確表明您已經有了相關的行中,你的數據庫,嘗試找出爲什麼你保存的事件兩次,一切都很好。你可能會增加也日誌條目源。

+0

是的,我承認這一點。我猜測引發我循環的東西是hibernate的saveOrUpdate沒有有這個問題。雖然我知道merge和saveOrUpdate有微妙的不同,但我的印象是,這是它應該能夠處理的一種情況。對於它的價值,我最終基本上做了你的建議 - 我刪除了所有可能匹配的記錄,然後填寫新的記錄。這似乎並不是它應該如何工作。 –

+0

對不起,我誤解了你的問題。確實,如果給定的ID已經存在,合併現有實體應該更新它們。 – KLHauser