У меня есть один метод, в котором есть запрос на слияние. Если запись уже отсутствует, этот метод вставляет новую строку, а если уже присутствует, обновляет существующую запись.
Проблема в этом методе заключается в том, что 2 потока выполняют этот метод одновременно. Первый поток входит в метод и не фиксирует транзакцию, и в то же время второй поток входит. Теперь один из них вставляет строку, второй также пытается вставить вместо обновления и вызывает уникальную ошибку ограничения.
Мне интересно, почему это происходит, второй поток должен обновить вместо вставки новой строки.
Я новичок в спящем режиме. Так это проблема транзакции гибернации или что-то еще.
Пожалуйста, помогите мне понять это. Благодарю.
Ниже приведен код mergeFunction (), добавленный для ясности. когда смоделированная строка журнала напечатана в следующей последовательности
обновление MY_TABLE ... thread-1
обновление MY_TABLE ... thread-2
обновлено MY_TABLE ... thread-1
Ошибка ограничения уникального ключа ... thread-2
Эта проблема моделируется только несколько раз. К счастью, 2 потока пытаются выполнить один и тот же метод.
public void mergeFunction(long customerId, long assetId, String module, Status status, String errorMsg) {
log.debug("Updating MY_TABLE for asset {} module {} status ={} customer ={}", assetId, module, status.name(),customerId);
StatelessSession statelessSession = session.getSessionFactory().openStatelessSession();
try {
Transaction tx = statelessSession.beginTransaction();
try {
String sql = "merge into MY_TABLE x " +
"using (select " + customerId + " customer_id, '" + module + "' module, " + assetId + " asset_id from dual) y " +
"on (x.asset_id = y.asset_id and x.module = y.module) " +
"when matched then " +
" update set x.status = :status, x.ERROR = :errMsg where x.asset_id = :aid and x.module = :module " +
"when not matched then " +
" insert (id, uuid, customer_id, module, asset_id, status, activated_on) " +
" values (id_MY_TABLE.nextval, portal_pck.get_uuid(), " + customerId + ", '" + module + "', " + assetId + ", '" + status + "', sysdate)";
statelessSession.createSQLQuery(sql).setParameter("aid", assetId)
.setParameter("module", module)
.setParameter("status", status.name())
.setParameter("errMsg", StringUtils.isEmpty(errorMsg) ? " " : errorMsg)
.executeUpdate();
tx.commit();
log.debug("Updated MY_TABLE for {} asset for {} status ={} customer={}",assetId,module, status.name(),customerId);
} catch (Exception exe) {
log.debug("error while updating MY_TABLE table for asset {} module{} status {} for customer {} exception ={}",
assetId, module, status.name(), customerId, exe);
tx.rollback();
throw exe;
}
} finally {
statelessSession.close();
}
}