使用 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=MERGE
或cascade=ALL
注释。 对于由来自 X 的关系引用的所有实体 Y,具有 级联元素值cascade=MERGE
或cascade=ALL
,Y递归合并 作为 Y'。对于所有这样的 Y 引用 X, X' 设置为参考 Y'。 (笔记 如果 X 是托管的,那么 X 是 与 X' 相同的对象。) 如果 X 是合并到 X' 的实体,并引用另一个实体 Y,其中cascade=MERGE
或cascade=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方法的使用