Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用JPA一次性创建新实体或更新现有实体_Jpa_Insert Update - Fatal编程技术网

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

使用JPA一次性创建新实体或更新现有实体,jpa,insert-update,Jpa,Insert Update,A有一个JPA实体,该实体具有时间戳字段,并通过复杂标识符字段进行区分。我需要的是更新已经存储的实体中的时间戳,否则创建并存储具有当前时间戳的新实体 事实证明,这项任务并不像乍一看那么简单。问题是,在并发环境中,我得到了令人讨厌的“唯一索引或主键冲突”异常。这是我的密码: // Load existing entity, if any. Entity e = entityManager.find(Entity.class, id); if (e == null) { // Could not

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
,因此它们将尝试同时保存两个或多个实体,使用相同的标识符导致错误

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

  • 当然我可以用全局锁同步这个代码块,以防止并发访问数据库,但这是最有效的方法吗
  • 一些数据库支持非常方便的
    MERGE
    语句,该语句更新现有行或在不存在行时创建新行。但我怀疑OpenJPA(我选择的JPA实现)是否支持它
  • 事件如果JPA不支持SQL合并,我总是可以退回到普通的旧JDBC,对数据库做任何我想做的事情。但我不想离开舒适的API,而把毛茸茸的JDBC+SQL组合搞得一团糟
  • 这里有一个魔术,可以只使用标准JPAAPI来修复它,但我还不知道

  • 请提供帮助。

    您指的是JPA交易的交易隔离。即,当事务访问其他事务的资源时,事务的行为是什么

    根据:

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

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

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


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

    两个链接都断开了