jpa - 使用 JPA 一次性创建新实体或更新现有实体

标签 jpa insert-update

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();

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

当两个或多个线程并行运行此代码块时,它们可能同时得到 null来自 entityManager.find(Entity.class, id)方法调用,因此他们将尝试同时保存两个或多个实体,使用相同的标识符导致错误。

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

  • 请帮忙。

    最佳答案

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

    根据this article :

    READ_COMMITTED is the expected default Transaction Isolation level for using [..] EJB3 JPA



    这意味着 - 是的,您将遇到上述代码的问题。

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

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

    关于jpa - 使用 JPA 一次性创建新实体或更新现有实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2336521/

    相关文章:

    MySQL:批量插入新记录或增加现有记录

    php - 在一个进程中在不同表中插入和更新

    mysql - 在 MySQL 数据库的列上设置 'NOT NULL' 属性的查询应该是什么?

    mysql - INSERT INTO ... SELECT FROM ... ON DUPLICATE KEY UPDATE

    jpa - 可移植 JPA 批量/批量插入

    java - 在 hibernate 中使用 EXISTS 仅返回一行以提高性能(不使用 setMaxResult)

    c# - 字段列表错误中的MySql未知列

    java - 处理延迟加载的 EJB JPA 实体的 JAX-WS 代理对象的最佳方法是什么?

    java - hibernate :级联类型

    java - 使用 Spring Data 审计数据库记录更改