mysql – 如果主键是由数据库生成的,如何使用em.merge()为jpa实体插入或更新?

前端之家收集整理的这篇文章主要介绍了mysql – 如果主键是由数据库生成的,如何使用em.merge()为jpa实体插入或更新?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我有一个像这样的JPA实体:

@Entity
@Table(name = "category")
public class Category implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @Column(name = "name")
    private String name;

    @OneToMany(cascade = CascadeType.ALL,mappedBy = "category")
    private Collection

使用MysqL作为底层数据库. “name”被设计为唯一键.使用Hibernate作为JPA提供程序.

使用merge方法的问题是因为pk是由db生成的,所以如果记录已经存在(名称已经存在),那么Hibernate会尝试将其插入到db中,我将获得一个唯一的键约束违例异常而不是更新.有没有人有一个很好的做法来处理?谢谢!

P.S:我的解决方法是这样的:

public void save(Category entity) {

    Category existingEntity = this.find(entity.getName());
    if (existingEntity == null) {
       em.persist(entity);
       //code to commit ...
    } else {
        entity.setId(existingEntity.getId());
        em.merge(entity);
        //code to commit ...
    }
}

public Category find(String categoryName) {
    try {
        return (Category) getEm().createNamedQuery("Category.findByName").
                setParameter("name",categoryName).getSingleResult();
    } catch (NoResultException e) {
        return null;

    }
}
最佳答案

How to use em.merge() to insert OR update for jpa entities if primary key is generated by database?

无论您是否使用生成的标识符,IMO都无关紧要.这里的问题是你想在一些唯一的密钥上实现“upsert”而不是PK和JPA并没有真正提供对它的支持(merge依赖于数据库身份).

所以你有AFAIK 2选项.

首先执行INSERT并在失败的情况下实施一些重试机制,因为存在唯一的约束违规,然后查找并更新现有记录(使用新的实体管理器).

或者,首先执行SELECT,然后根据SELECT的结果插入或更新(这就是你所做的).这可以工作,但不是100%保证,因为你可以在两个并发线程之间有一个竞争条件(他们可能找不到给定categoryName的记录并尝试并行插入;最慢的线程将失败).如果不太可能,这可能是一个可接受的解决方案.

更新:如果您不介意使用MysqL专有功能,可能会有第三个奖励选项,请参阅12.2.5.3. INSERT … ON DUPLICATE KEY UPDATE Syntax.但从未使用JPA进行过测试.

猜你在找的MySQL相关文章