Spring - вместо одного выполняются два запроса на обновление hibernate - PullRequest
0 голосов
/ 26 июня 2018

Я работаю в Spring и Hibernate. У меня есть требование, где мне нужно обновить определенное поле, добавив к нему номер. Поскольку несколько потоков могут выполнять его одновременно, при обновлении я проверяю значение поля со старым значением. Поэтому, если ничего не было обновлено, это означает, что оно было увеличено каким-то другим потоком, и мы запускаем попытку.

CompanyService

public Company getAndIncrementRequestId(final int companyId, int retry) throws Exception {
    Optional<Company> companyOptional = companyRepository.findById(companyId);
    if (!companyOptional.isPresent()) {
        throw new EntityNotFoundException("Company not found for given id" + companyId);
    }

    Company company = companyOptional.get();
    int oldRequestId = company.getRequestId();
    int requestId;
    if (oldRequestId == Integer.MAX_VALUE) {
        requestId = 1;
    } else {
        requestId = oldRequestId + 1;
    }
    company.setRequestId(requestId); //--------------------------> PROBLEM
    int result = companyRepository.updateRequestId(companyId, requestId, oldRequestId);
    if (result == 0) {
        if (retry < 0) {
            throw new Exception("Unable to get requestId");
        }
        LOG.warn("Retrying since there was some update on requestId by some other thread");
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            LOG.warn("Unexpected InterruptException occurred while trying to get requestId");
        }
        return getAndIncrementRequestId(companyId, retry - 1);
    }
    return company;
}

CompanyRepository

@Transactional
public interface CompanyRepository extends CrudRepository<Company, Integer> {
    Optional<Company> findById(String id);

    @Modifying(clearAutomatically = true)
    @Query("update Company c set c.requestId = :requestId WHERE c.id = :companyId AND c.requestId = :oldRequestId")
    int updateRequestId(@Param("companyId") Integer companyId, @Param("requestId") Integer requestId,@Param("oldRequestId") Integer oldRequestId);
}

Но этот приведенный выше код в Service вызовет два обновления гибернации, одно из которых устанавливает requestId с последним requestId, а другое - фактическое обновление. После установки show-sql как true может наблюдаться два запроса в журнале.

Но если линия,

company.setRequestId (RequestID);

Перемещается вниз после того, как companyRepository.updateRequestId () работает нормально.

Рабочая компанияСервис

public Company getAndIncrementRequestId(final int companyId, int retry) throws Exception {
    Optional<Company> companyOptional = companyRepository.findById(companyId);
    if (!companyOptional.isPresent()) {
        throw new EntityNotFoundException("Company not found for given id" + companyId);
    }

    Company company = companyOptional.get();
    int oldRequestId = company.getRequestId();
    int requestId;
    if (oldRequestId == Integer.MAX_VALUE) {
        requestId = 1;
    } else {
        requestId = oldRequestId + 1;
    }

    int result = companyRepository.updateRequestId(companyId, requestId, oldRequestId);
    if (result == 0) {
        if (retry < 0) {
            throw new Exception("Unable to get requestId");
        }
        LOG.warn("Retrying since there was some update on requestId by some other thread");
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            LOG.warn("Unexpected InterruptException occurred while trying to get requestId");
        }
        return getAndIncrementRequestId(companyId, retry - 1);
    }
    company.setRequestId(requestId); //--------------------------> PROBLEM DOES NOT EXISTS
    return company;
}

Sp мой вопрос, почему есть два запроса, когда я нигде не передал юридическое лицо Company ..?

1 Ответ

0 голосов
/ 26 июня 2018

Это потому, что когда вы делаете "companyRepository.findById (companyId);" возвращенная компания возвращается в управляемом состоянии. Таким образом, когда в случае 1 вы устанавливаете идентификатор запроса перед вызовом «companyRepository.updateRequestId (companyId, requestId, oldRequestId);», в хранилище компании создается объект транзакции, который выполняет все ожидающие обновления управляемого объекта, а также запрос метод "updateRequestId" также запускается. В то время как во втором случае, поскольку вы написали оператор set после вызова «companyRepository.updateRequestId (companyId, requestId, oldRequestId);», именно поэтому обновление управляемого объекта никогда не запускается, потому что оно не получает транзакцию

...