Предотвращение сохранения изменений в спящем объекте - PullRequest
0 голосов
/ 17 октября 2019

Я обновляю свое приложение из Spring Boot 1.4.5 / Hibernate 4.3.5 до Spring Boot 2.0.9 / Hibernate 5.2.18, и код, который раньше работал в предыдущей конфигурации, больше не работает.

Сценарий выглядит следующим образом:

  1. Запустите транзакцию, введя метод, аннотированный @ Transactional
  2. Гидратируйте объект
  3. Измените объект
  4. Сделайте еще один запрос
  5. Обнаружите проблему. В результате этой проблемы определите, что изменения не должны сохраняться.
  6. Исключить сущность
  7. Выйти из метода / транзакции

В Hibernate 4.3.5 вызовentityManager.detach () предотвратит сохранение изменений. Однако в Hibernate 5.2.18 я обнаружил, что изменения сохраняются даже с этим вызовом. Я также попытался исключить () из сеанса, и я попытался очистить () все сущности из сеанса (просто чтобы посмотреть, что произойдет).

Поэтому я спрашиваю - возможно ли отменить изменения сущностей в Hibernate 5.2.18 так, как я смог это сделать в Hibernate 4.3.5?

Соответствующий код приведен ниже ...

@Entity
public class Agreement {

    private Long agreementId;
    private Integer agreementStateId;

    @Id
    @Column(name = "agreement_id")
    public Long getAgreementId() {
        return agreementId;
    }

    public void setAgreementId(Long agreementId) {
        this.agreementId = agreementId;
    }

    @Basic
    @Column(name = "agreement_state_id", nullable = false)
    public Integer getAgreementStateId() {
        return agreementStateId;
    }

    public void setAgreementStateId(Integer agreementStateId) {
        this.agreementStateId = agreementStateId;
    }
}


@Component
public class Repo1 {

    @PersistenceContext(unitName = "rights")
    private EntityManager entityManager;

    public void evict(Object entity) {
        entityManager.detach(entity);
    }

    public Agreement getAgreement(Long agreementId) {
        // Code to get entity is here.
        // Agreement with an agreementStateId of 5 is returned.
    }

    public void anotherQuery() {
        // Code to make another query is here.
    }
}


@Component
public class Service1 {

    @Autowired
    Repo1 repo;

    @Transactional
    public void doSomething() {
        Agreement agreement = repo.getAgreement(1L);

        // Change agreementStateId.  Very simple for purposes of example.
        agreement.setAgreementStateId(100);

        // Make another query
        repo.anotherQuery();

        // Detect a problem here. Simplified for purposes of example.
        if (agreement.getAgreementStateId() == 100) {
            repo.evict(agreement);
        }
    }
}

1 Ответ

0 голосов
/ 21 октября 2019

Я нашел проблему, и она не имеет ничего общего с evict (). Оказывается, дополнительный запрос вызывал сброс сеанса до вызова evict ().

Как правило, приложение использует QueryDSL для выполнения запросов. Выполненные таким образом запросы не приводили к сбросу сеанса до выполнения запроса. Однако в этом случае запрос был создан с помощью Session.createSQLQuery (). При этом используется FlushMode, уже назначенный для сеанса, который был FlushMode.AUTO.

Мне удалось предотвратить сброс, вызвав setHibernateFlushMode (FlushMode.COMMIT) для запроса перед выполнением запроса. Это приводит к временному изменению сеанса FlushMode до тех пор, пока не будет выполнен запрос. После этого вызов evict () работал как положено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...