使用JPA一次性创建新实体或更新现有实体
A有一个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
// 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交易的交易隔离。即,当事务访问其他事务的资源时,事务的行为是什么 根据: READ_COMMITTED是使用[…]EJB3 JPA的预期默认事务隔离级别 这意味着-是的,您将遇到上述代码的问题 但是JPA不支持自定义隔离级别
更广泛地讨论这个话题。根据您是使用Spring还是EJB,我认为您可以使用适当的事务策略。两个链接都断开了