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;
}
}
是的,我承認這一點。我猜測引發我循環的東西是hibernate的saveOrUpdate沒有有這個問題。雖然我知道merge和saveOrUpdate有微妙的不同,但我的印象是,這是它應該能夠處理的一種情況。對於它的價值,我最終基本上做了你的建議 - 我刪除了所有可能匹配的記錄,然後填寫新的記錄。這似乎並不是它應該如何工作。 –
對不起,我誤解了你的問題。確實,如果給定的ID已經存在,合併現有實體應該更新它們。 – KLHauser