Объединить и получить версию без обновления? - PullRequest
7 голосов
/ 11 марта 2011

Можно ли изменить экземпляр версионного объекта и получить версию для увеличения без использования flush?Потому что из того, что я прочитал, я боюсь, что очистка не очень хорошая практика, потому что это плохо влияет на производительность или даже повреждение данных?Я не уверен: D


Вот простой код, а также вывод в виде комментария:

/*
    Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, ... too long
    the version before modification : 16
    the version after modification : 16
    after merge the modification, the version is : 16
    Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?,  ... too long
    after flushing the modification, the version is finally : 17
*/
public void modifyHeaderAndGetUpdatedVersion() {
    String id = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, id);
    System.out.println("the version before modification : " + receivingGood.getVersion());

    receivingGood.setTransactionNumber("NUM001xyz");
    System.out.println("the version after modification : " + receivingGood.getVersion());

    receivingGood = em.merge(receivingGood);
    System.out.println("after merge the modification, the version is : " + receivingGood.getVersion());

    em.flush();
    System.out.println("after flushing the modification, the version is finally : " + receivingGood.getVersion());
}

В моем тесте версия была увеличена после сброса.Экземпляр, возвращенный из операции слияния, не имеет увеличенной версии.

Но в моем случае я хотел бы вернуть сущность в мой webui в форме DTO, и сущность должна иметь версию version-after-очистить / зафиксировать перед преобразованием его в DTO и возвратом в пользовательский интерфейс для визуализации.И тогда пользовательский интерфейс может иметь самую последнюю версию, и передаст эту версию для следующего представления.


Есть ли способ получить последнюю версию без выполнения сброса?

Спасибо!


ОБНОВЛЕНИЕ


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

Первый - синхронизировать изменения в соединении базы данных, чтобы вызов хранимой процедуры из того же соединения мог видеть изменения, сделанные из entityManager.

Второй флеш вызывается для получения финальной версии.И мы видим, что это увеличивается вдвое .Таким образом, получение версии только из ручного приращения без сброса не будет работать в этом состоянии, так как мы должны реально посчитать, сколько выполняется сбросов.

/*
Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, .. too long
the version before modification : 18
the version after modification : 18
after merge the modification, the version is : 18
now flushing the modification, so that the stored procedure call from the same connection can see the changes
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, .. too long
after flushing the modification, the version is : 19
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, .. too long
after the second flush, the version got increased again into : 20
*/
public void modifyHeaderAndGetUpdatedVersionWith2Flushes() {
    String id = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, id);
    System.out.println("the version before modification : " + receivingGood.getVersion());

    //auditEntity(receivingGood, getUser("3978fee3-9690-4377-84bd-9fb05928a6fc"));
    receivingGood.setTransactionNumber("NUM001xyz");
    System.out.println("the version after modification : " + receivingGood.getVersion());

    receivingGood = em.merge(receivingGood);
    System.out.println("after merge the modification, the version is : " + receivingGood.getVersion());
    System.out.println("now flushing the modification, so that the stored procedure call from the same connection can see the changes");
    em.flush();
    System.out.println("after flushing the modification, the version is : " + receivingGood.getVersion());

    receivingGood.setTransactionNumber("NUM001abc");

    em.flush();
    System.out.println("after the second flush, the version got increased again into : " + receivingGood.getVersion());
}

Означает ли это, что я действительно должен зависеть от сброса приконец, чтобы получить последнюю версию для измененного объекта?


ОБНОВЛЕНИЕ 2


Вот простой пример метода службы, который обновит объект ReceivingGood и должен вернутьDTO с самой новой версией.

public ReceivingGoodDTO update(ReceivingGood entity) {
  // merge it
  entity = entityManager.merge(entity);

  // the version is not incremented yet, so do the flush to increment the version
  entityManager.flush(); // if i dont do this, the dto below will get the unincremented one

  // use a mapper, maybe like dozer, to copy the properties from the entity to the dto object, including the newest version of that entity
  ReceivingGoodDTO dto = mapper.map(entity, dto);

  return dto;
}

, и вот пример, который использует этот метод:

@Transactional
public ReceivingGoodDTO doSomethingInTheServiceAndReturnDTO() {
  // do xxx ..
  // do yyy ..
  dto = update(entity);
  return dto; // and the transaction commits here, but dto's version isnt increased because it's not a managed entity, just a plain POJO
}

Ответы [ 2 ]

5 голосов
/ 11 марта 2011

Я снова рекомендую прочитать больше о Hibernate и о том, как он работает, будь то его документация или «Сохранение Java с Hibernate».

Вы видите это в операции сброса, потому что именно там происходят обновления базы данных.Если вы просто пропустите сброс и подтвердите транзакцию, вы увидите то же самое поведение.Это означает, что всякий раз, когда ваша единица работы заканчивается, Hibernate будет сбрасывать изменения в базу данных.Именно на этом этапе Hibernate сравнивает и обновляет номер версии.Если версия базы данных - 17, а вы обновляете версию 16, Hibernate выдаст исключение об обновлении устаревшего объекта.

Тем не менее, вы можете «предсказать», какая будет следующая версия, увеличивая 1 на значение, которое вы в настоящее время имеете в своем экземпляре.Но это никогда не будет реальным, потому что оно эффективно увеличивается только перед обновлением записи базы данных.Таким образом, любые параллельные изменения не будут видны вашему потоку, если вы не запросите базу данных.

Редактировать:

Вы видите два приращения, потому что вы делаете два сброса.«Версия» - это техника для «оптимистической» блокировки. Это означает, что вы ожидаете, что только один поток будет обновлять запись в течение любой единицы работы (в более широком смысле это «действие пользователя», где он перечисляетзаписи, выберите один и обновляет его).Его цель - избежать обновления устаревшего объекта в Hibernate, когда два пользователя выбирают одну и ту же запись для редактирования, вносят некоторые параллельные изменения и обновляют ее.Одно из правок должно быть отклонено, а первое, попавшее в базу данных, побеждает.Когда вы обновляете запись дважды (дважды вызывая flush), вы видите два приращения.Но на самом деле речь идет не о сбросах, а об «обновлениях в базе данных».Если бы у вас было две транзакции, вы бы увидели одинаковое поведение.

Тем не менее, стоит отметить, что этой техникой должен управлять Hibernate.Вы не должны увеличивать это самостоятельно.Часто хорошей практикой является не предоставлять сеттеры для таких полей.

Другими словами: вы должны рассматривать «версию» как значение, доступное только для чтения, и что вы не можете его контролировать.Таким образом, для пользователя безопасно отображать его значение на экране, но не безопасно манипулировать им (или «определять» следующую версию).Самое большее, вы можете сделать «наилучшее предположение», предсказав, что это будет current_version + 1.

0 голосов
/ 11 марта 2011

Последняя версия является текущей + 1. Вы можете увеличить версию самостоятельно в методе entityToDto ().

Но в вашем примере выполнение сброса не вызовет такой проблемы с производительностью, IMO, поскольку Hibernate все равно сделает это во время фиксации. Будет два сброса, но у второго больше не будет смыва.

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