我读了JPA caches SQL instructions以提高效果:
像Hibernate这样的JPA提供程序可以缓存它们的SQL指令 应该发送到数据库,通常直到你实际提交 交易。例如,你调用em.persist(),Hibernate记得 它必须使数据库INSERT,但实际上不执行 直到你提交交易为止。
我将一个Java EE 6应用程序部署到具有两个实例的Glassfish集群。在应用程序中存在竞争条件,其中两个单身人员执行一些昂贵的查询,然后将结果缓存在数据库表中。他们正在做同样的工作,并试图写相同的记录,所以我有时会得到一个例外:
java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (SOMESCHEMA.SOMETABLE_PK) violated
我认为最简单的方法是捕捉并忽略异常:
// In a EJB with container-managed transactions.
public Entity getExpensiveEntity(int entityId) {
Entity entity = entityManager.find(Entity.class, entityId);
if (entity == null) {
try {
result = expensiveQueries();
entityManager.persist(result);
entityManager.flush();
} catch (SQLIntegrityConstraintViolationException ex) {
// The other instance already created the result, so get it.
result = jpa.find(result.getId());
}
}
return result;
}
我认为调用flush
是必要的,否则SQLIntegrityConstraintViolationException将不会发生,直到事务在EJB调用堆栈的某个地方结束,过去捕获和忽略。我是否正确,这是flush
的有效用例吗?有没有更好的方法来解决这个问题?