JPA: разрешить состояние гонки для записи после чтения
Я хочу хранить уникальные сущности с их хэшами. Сущность состоит из сгенерированного идентификатора и значения хеша, которое должно быть уникальным. Я делаю это с этим кодом:
@Stateless
@LocalBean
public class srvcEntity {
@PersistenceContext(unitName = "mine")
private EntityManager em;
private Long save(byte[hash]) {
List<Entity> list = Entity.findByHash(hash, em); // using TypedQuery.getResultList()
if (list != null && list.size() > 0) {
entityId = list.get(0).getId();
} else {
Entity e = Entity.save(hash, em); // using em.persist()
if (e != null) {
entityId = e.getId();
}
}
return entityId;
}
}
Это работает очень хорошо, пока я не получу много сущностей для хранения одновременно. Тогда условие гонки может привести к тому, что во время чтения не будет найдена ни одна сущность с данным хешем, но во время сохранения я получаю исключение ConstraintViolationException для дублирующего хеша.
Поскольку мой код существует в компоненте с транзакциями на основе контейнеров, я просто не могу прочитать снова после сбоя сохранения.
Как я могу решить это состояние гонки?
2 ответа
Прямой способ - перехватить исключение, а затем снова выполнить чтение.
Вы также можете использовать полосатый замок, который предотвратит состояние гонки. Это полезно в ситуациях, когда вы не хотите выполнять какую-либо операцию, возможно, дважды, но это также включает в себя блокировку (хотя Guava Striped
класс позволяет настроить количество блокировок и, следовательно, пропускную способность довольно приятно).
Методы EJB синхронизированы. Если вы используете только один экземпляр вашего приложения (оно не кластеризовано!), Тогда
@Singleton
может решить эту проблему, так как для этого кода должна быть только одна точка входа, которая исключила бы возможность состояния гонки.