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 事务的事务隔离。 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/