【问题标题】:Recommended behaviour for update () method in DAO using EntityManager (JPA)?使用 EntityManager (JPA) 在 DAO 中更新 () 方法的推荐行为?
【发布时间】: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 时是否可以创建新条目?

【问题讨论】:

    标签: spring hibernate jpa dao entitymanager


    【解决方案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 需要手动更新关系。
    猜你喜欢
    • 2010-12-21
    • 2013-06-05
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 2017-04-07
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多