Java JPA merge为键';初级';冲水时

Java JPA merge为键';初级';冲水时,java,mysql,spring,hibernate,jpa,Java,Mysql,Spring,Hibernate,Jpa,我有一个使用hibernate 5.2和JPA处理数据库的spring服务器 我们有一个收集大量数据并根据这些数据保存事件的过程。它每天运行,这些事件可能会改变值。有时,当我尝试保存这些时,会出现以下异常: 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 'PRIMAR

我有一个使用hibernate 5.2和JPA处理数据库的spring服务器

我们有一个收集大量数据并根据这些数据保存事件的过程。它每天运行,这些事件可能会改变值。有时,当我尝试保存这些时,会出现以下异常:

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!");
        }
    }
}

明确表示数据库中已有相关行。试着找出为什么保存事件两次,一切正常。您还可以将日志条目添加到源中。

是的,我知道这一点。我想让我陷入困境的是hibernate的saveOrUpdate没有这个问题。虽然我知道merge和saveOrUpdate有细微的不同,但我觉得这是它应该能够处理的情况之一。不管它值多少钱,我最终基本上按照你的建议做了——我删除了所有可能匹配的过去记录,然后填充新记录。只是看起来它不应该是这样工作的。对不起,我误解了你的问题。事实上,如果给定id已经存在,则合并现有实体应更新它们。
@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;
    }
}
Duplicate entry 'VAL-below_avg-2017-04-07' for key 'PRIMARY'