Java 持久化一个新的但相同的实体,JPA报告重复条目

Java 持久化一个新的但相同的实体,JPA报告重复条目,java,mysql,jpa,entitymanager,Java,Mysql,Jpa,Entitymanager,我有一个连接到MySQL数据库的JPA项目,其中我的实体对象映射到一个表,该表有两列约束。即: @Entity @Table(name = "my_entity") class MyEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") private Integer id; @Bas

我有一个连接到MySQL数据库的JPA项目,其中我的实体对象映射到一个表,该表有两列约束。即:

@Entity
@Table(name = "my_entity")
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "myField1")
    private String myField1;
    @Basic(optional = false)
    @Column(name = "myField2")
    private int myField2;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "myEntity")
    private Set<OtherEntity> otherEntitySet;
}
这给了我一个MySQLIntegrityConstraintViolationException,抱怨这是一个重复条目。我想这是因为它试图在删除旧条目之前添加新条目。有什么办法维持秩序吗?或者,有没有办法使用JPA来防止这种情况?这并不是一个常见的用例,但我担心的是一个用户试图删除一个实体,以摆脱所有关联的数据并重新开始,然后重新创建更简单的字段,然后发现数据从未被删除

hashCode和equals实现如下所示:

public int hashCode() {
    int hash = 0;
    hash += (getMyField1().hashCode() + getMyField2());
    return hash;
}

public boolean equals(Object object) {
    if (!(object instanceof MyEntity)) {
        return false;
    }
    MyEntity other = (MyEntity) other;
    return (getMyField2() == other.getMyField2()) &&
        (getMyField1().equals(other.getMyField1()));
}

我认为在JPA中没有任何标准的方法来指定操作顺序,因此无法保证语句将以何种顺序执行。理想情况下,JPA实现将足够聪明,能够检测到这种情况并在插入之前执行删除,但这是他们经常失败的地方。或者,如果您的数据库支持延迟约束检查(例如,Oracle支持,但MySQL不支持),则数据库将通过等待提交时间来处理此问题,以给出唯一的约束冲突异常


因此,一种解决方案是在调用remove(entity1)之后执行额外的提交。另一种可能是,在创建entity2之前,首先检查数据库中是否存在entity2,如果存在,就使用该entity2。这两个选项都有点麻烦,不适合所有工作流。您可能想深入了解当前JPA实现的文档,看看它们是否提供了任何可能有用的扩展。

我也遇到过同样的问题,涉及UC和错误顺序发生的插入/删除。我必须为我的实体创建一个匹配UC列的复合键。之后,删除和插入按正确的顺序进行。请参阅本文以及有关添加@EmbeddedId的评论:


您可以添加equals和hashCode实现吗?添加--我最初在equals中有一个检查Id的快捷方式,但为了确保这一点,我删除了它。同样的问题。这无疑为我指明了正确的方向。我现在看到对JPA的引用(我特别使用EclipseLink)在默认情况下先插入后删除。应用程序允许用户随时保存或取消,因此我无法在删除后进行提交,但我正在研究更改默认设置或构建重用功能。我怀疑您想说的是:删除后的显式
flush()
(entity1)。无需承诺,这是一个坏主意(最好将整个方法放在一个TRA中),我想我已经了解了总体思路,但我对细节有点迷茫。你能举个简单的例子吗?比如说,如果我有一个简单的联系人信息表呢。在数据库中,我对这个人的名字(id int,name varchar)有一个唯一的限制,其他表链接到这个id。我编辑我的通讯录,然后说,“哦,我不再是Eddie的朋友了”,所以我删除了这个条目,并将其与任何其他相关数据级联。但在更新了其他人的信息后(没有保存),我输入了“Eddie”作为其他人的条目。在我设计的JPA下,这会抛出一个错误。
public int hashCode() {
    int hash = 0;
    hash += (getMyField1().hashCode() + getMyField2());
    return hash;
}

public boolean equals(Object object) {
    if (!(object instanceof MyEntity)) {
        return false;
    }
    MyEntity other = (MyEntity) other;
    return (getMyField2() == other.getMyField2()) &&
        (getMyField1().equals(other.getMyField1()));
}