Есть сущность с id и каким-то другим уникальным ключом (extId). Множество потоков (приложений) вставляют в БД сущности с незаполненным id, но известным extId по следующей логике:
extId уже найден в БД, то обновить сущность новыми данными.@Transactional(propagation = REQUIRED_NEW)
public A createOrUpdate(A a) {
A b = findByExtId(a.extId, LockModeType.PESSIMISTIC_WRITE);
if (b != null) {
a.id = b.id
}
return save(a); // hibernate merge
}
Update:
@Transactional(propagation = Propagation.SUPPORTS)
public A findByExtId(final Long extId,
final LockModeType lockMode) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<A> cq = cb.createQuery(A.class);
Root<A> root = cq.from(A.class);
cq.where(cb.equal(root.get("extId"), cb.parameter(Long.class, "extId")));
TypedQuery<A> query = entityManager.createQuery(cq);
query.setParameter("extId", extId);
query.setLockMode(lockMode);
List<A> list = query.getResultList();
if (!list.isEmpty()) {
return list.get(0);
}
return null;
}
@Transactional(propagation = Propagation.SUPPORTS)
public A save(A t) {
return entityManager.merge(t);
}
Проблема в том, что данный код в редких случаях все равно вставляет сущность с одинаковым extId несколько раз. В чем может быть причина?
База данных PostgreSQL.
Если два потока (с одним и тем же extID) примерно одновременно выполнят A b = findByExtId(a.extId, LockModeType.PESSIMISTIC_WRITE); и в БД еще нет строки с таким extID, то они оба вставят новую строчку
Потому что для обновления используется другая команда сессии.
session.update(a); или session.merge(a);
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости