创建新的或更新现有实体A具有一个具有时间戳字段并由复杂标识符字段进行区分的JPA实体。我需要的是在已存储的实体中更新时间戳,否则使用当前时间戳创建并存储新实体。使用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 MERGE,我总是可以回退到普通的旧JDBC并对数据库做任何我想做的事情。但是我不想留下舒适的API,并且不愿意使用大量的JDBC + SQL组合。
- 只有使用标准的JPA API才能修复它,但我还不知道它。
请帮忙。
两条链路都断开 – Sergey 2018-01-24 05:17:23