Я попытаюсь описать мою проблему в уровнях изоляции транзакций JPA.
Структура базы данных:
Table1
-> с PK, определенным как дата ('ddMMyyyy') Table2
-> с FK в Table1
JPA (уровень изоляции :: read_commited
) - код:
Query query = em.createQuery("from Table1 trd where trd.id = :d");
query.setParameter("d", date);
Table1 t = null;
try{
t = (Table1) query.getSingleResult();
}catch(javax.persistence.NoResultException e){
t = null;
}
if(t==null){
t=new Table1 (date);
em.persist(trd);
}
for(Table2 q:tables2){
q.setTable1(t);
em.merge(q);
}
Таким образом, процедура проверяет, существует ли запись в БД и, если нет, создайте новую.Метод полностью совместим, если система основана на одном потоке.В противном случае возможна ситуация, подобная этой:
- Поток 1: Проверьте, существует ли сущность, представленная по дате, в базе данных
- Поток 2: Сделайте точно так же
Они оба считают, что такой записи еще не было, поэтому добавьте новую.Все хорошо до момента совершения транзакции.Первый будет передан без каких-либо исключений, купите второе исключение для повышения, связанное с дублированием первичного ключа.
Есть ли возможность сохранить такую ситуацию, кроме изменения уровня изоляции на SERIALIZABLE
?