使用 EntityManager (JPA) 在 DAO 中更新 () 方法的推荐行为?

Posted

技术标签:

【中文标题】使用 EntityManager (JPA) 在 DAO 中更新 () 方法的推荐行为?【英文标题】:Recommended behaviour for update () method in DAO using EntityManager (JPA)? 【发布时间】:2014-12-08 06:38:00 【问题描述】:

我有一个带有基本 CRUD 方法的 REST 服务来创建/读取/更新/删除我的资源。

我的更新 DAO 实现如下所示:

@Override
public Entity update(Entity entity) 
    final Entity updatedEntity = em.merge(entity);
    em.flush();
    return updatedEntity;

现在我不想“更新”数据库中不可用的资源。为了解决这个问题,我编写了一个服务,它首先使用提供的 id 对资源执行 get 调用。如果资源不可用,则抛出资源无法更新的异常...

但这意味着每个 REST 更新调用需要 2 次数据库调用。如果条目已经存在,是否有推荐的方法来编写抛出异常的 dao update() 方法?在对不存在的资源执行 PUT 时是否可以创建新条目?

【问题讨论】:

【参考方案1】:

merge() 方法持久化尚未持久化的实体(没有 ID 或版本),如果实体持久化,则更新该实体。因此,除了调用 merge()(并将此调用返回的值返回给 merge())之外,您无需执行任何操作。

这意味着,如果实体没有 ID,您将在 DB 上保留一条新记录。

    /**
     * Merge the state of the given entity into the
     * current persistence context.
     * @param entity  entity instance
     * @return the managed instance that the state was merged to
     * @throws IllegalArgumentException if instance is not an
     *         entity or is a removed entity
     * @throws TransactionRequiredException if invoked on a
     *         container-managed entity manager of type
     *         <code>PersistenceContextType.TRANSACTION</code> and there is
     *         no transaction
     */
    public <T> T merge(T entity);

3.2.4.1 合并分离实体状态

合并操作允许 从分离状态传播 实体到持久实体 由 EntityManager 管理。

合并操作的语义 应用于实体 X 如下:

如果 X 是分离的实体,则 X 的状态将复制到预先存在的 相同的托管实体实例 X' 身份或 X 的新托管副本 X' 已创建。 如果 X 是一个新的实体实例,则创建一个新的托管实体实例 X' X 的状态被复制到 新的托管实体实例 X'。 如果 X 是已删除的实体实例,则 IllegalArgumentException 将是 由合并操作(或 事务提交将失败)。 如果 X 是一个托管实体,它会被合并操作忽略, 但是,合并操作是 级联到引用的实体 来自 X 的关系,如果这些 关系已用 级联元素值 cascade=MERGEcascade=ALL 注释。 对于由来自 X 的关系引用的所有实体 Y,具有 级联元素值cascade=MERGEcascade=ALL,Y递归合并 作为 Y'。对于所有这样的 Y 引用 X, X' 设置为参考 Y'。 (笔记 如果 X 是托管的,那么 X 是 与 X' 相同的对象。) 如果 X 是合并到 X' 的实体,并引用另一个实体 Y,其中 cascade=MERGEcascade=ALL 是 未指定,则导航 来自 X' 的相同关联产生 对托管对象 Y' 的引用 与 Y 相同的永久身份。

持久性提供者不得 合并标记为 LAZY 的字段 已获取:它必须忽略此类 合并时的字段。

任何Version 使用的列 实体必须由 持久性运行时实现 在合并操作期间和/或在 刷新或提交时间。离席期间 Version 列中没有 额外的版本检查由 持久性提供程序运行时 在合并操作期间。

1#更新策略

public Entity update(Entity entity) 
    final Entity find = em.find(...);
    if(find == null)
        throw new Exception();
    
    //set ID into entity
    updatedEntity = em.merge(entity);
    return updatedEntity;

2#更新策略

@Transactional
public Entity update(Entity entity) 
    final Entity find = em.find(...);
    if(find == null)
        throw new Exception();
    
    //set into find each value that you want update
    //when the transaction is closed, it will be updated the entity
    return find;

尽量避免使用 em.flush() .. 不是最佳做法。

【讨论】:

在许多情况下,#2 策略是最佳选择,原因是合并增量计算很棘手,特别是当您有 @OneToMany -eager/lazy-relationships 时。另请记住,#2 需要手动更新关系。

以上是关于使用 EntityManager (JPA) 在 DAO 中更新 () 方法的推荐行为?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 EntityManager (JPA) 在 DAO 中实现 update() 方法?

使用 EntityManager (JPA) 在 DAO 中更新 () 方法的推荐行为?

一个创建函数可以使用 EntityManager (JPA) 处理任何类型的对象吗?

JPA的entityManager的findgetReferencepersisitremove方法的使用

无法在使用 Arquillian 和 WildFly 的 JPA 集成测试中注入 EntityManager

Spring+JPA EntityManager 注入 service 和 dao