1

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

@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;
}

在数据库中,my_entity 表对 (myField1, myField2) 具有唯一约束。问题是,如果我使用 EntityManager.remove(entity) 删除现有实体,然后使用 EntityManager.persist(entity) 添加新实体,则数据库会引发有关重复行的错误。

例如:

entityManager.getTransaction().begin();

MyEntity entity1 = new MyEntity();
entity1.setMyField1("Foo");
entity1.setMyField2(500);
entityManager.persist(entity1);

entityManager.getTransaction().commit();
entityManager.getTransaction().begin();

entityManager.remove(entity1);

MyEntity entity2 = new MyEntity();
entity2.setMyField1("Foo");
entity2.setMyField2(500); 
entityManager.persist(entity2);

entityManager.getTransaction().commit();

这给了我一个 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()));
}
4

2 回答 2

2

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

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

于 2009-12-19T15:43:35.303 回答
0

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

https://forum.hibernate.org/viewtopic.php?p=2382504

于 2010-01-20T18:07:47.447 回答