【问题标题】:Create new or update existing entity at one go with JPA使用 JPA 一次性创建新实体或更新现有实体
【发布时间】:2011-01-21 03:31:05
【问题描述】:

A 有一个 JPA 实体,该实体具有时间戳字段并由复杂的标识符字段区分。我需要的是更新已经存储的实体中的时间戳,否则使用当前时间戳创建和存储新实体。

事实证明,这项任务并不像第一眼看上去那么简单。问题是在并发环境中我得到了令人讨厌的“唯一索引或主键违规”异常。这是我的代码:

// Load existing entity, if any.
Entity e = entityManager.find(Entity.class, id);
if (e == null) {
  // Could not find entity with the specified id in the database, so create new one.
  e = entityManager.merge(new Entity(id));
}
// Set current time...
e.setTimestamp(new Date());
// ...and finally save entity.
entityManager.flush();

请注意,在此示例中,实体标识符不是在插入时生成的,而是预先知道的。

当两个或多个线程并行运行此代码块时,它们可能会同时从entityManager.find(Entity.class, id)方法调用中获取null,因此它们会尝试同时保存两个或多个具有相同标识符的实体导致错误。

我认为解决这个问题的方法很少。

  1. 我当然可以将此代码块与全局锁同步以防止对数据库的并发访问,但这会是最有效的方法吗?
  2. 一些数据库支持非常方便的MERGE 语句,可以更新现有行或在不存在时创建新行。但我怀疑 OpenJPA(我选择的 JPA 实现)是否支持它。
  3. 如果 JPA 不支持 SQL MERGE 事件,我总是可以退回到普通的旧 JDBC 并对数据库做任何我想做的事情。但我不想留下舒适的 API 并弄乱毛茸茸的 JDBC+SQL 组合。
  4. 有一个魔术技巧可以仅使用标准 JPA API 来修复它,但我还不知道。

请帮忙。

【问题讨论】:

    标签: jpa insert-update


    【解决方案1】:

    您指的是 JPA 事务的事务隔离。 IE。事务在访问其他事务的资源时的行为是什么。

    根据this article

    READ_COMMITTED 是使用 [..] EJB3 JPA 的预期默认事务隔离级别

    这意味着 - 是的,上面的代码会有问题。

    但 JPA 不支持自定义隔离级别。

    This thread 更广泛地讨论了该主题。根据您使用的是 Spring 还是 EJB,我认为您可以使用适当的事务策略。

    【讨论】:

    • 两个链接都坏了
    猜你喜欢
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多