CRUD.save () с отметкой времени из БД - PullRequest
0 голосов
/ 30 мая 2018

У меня есть приложение Spring, созданное на H2 и SqlServer.Я установил столбец объекта, например:

@Column(insertable = false, columnDefinition = "bigint default CURRENT_TIMESTAMP")

Теперь, когда я сохраняю новый объект, отметка времени устанавливается правильно.Однако, когда я изменяю сущность, метка времени будет той, которую я установил в объекте перед обновлением.Я знаю, что если я установлю updatable = false, то он снова обновится до current_timestamp, однако мне нужна гибкость, чтобы метка времени устанавливалась только в случае значительных изменений, т. Е. Если я изменяю поле комментария для объекта, я не хочуотметка времени изменяется, но если я изменяю поле владельца, я хочу, чтобы отметка времени была обновлена.

Я попытался установить значение на ноль, но это ничего не дает.Я не уверен, как я мог бы использовать метод @PreUpdate, чтобы получить CURRENT_TIMESTAMP из db, и я не знаю ни одного способа легко изменить crud.save ().Единственная альтернатива, о которой я могу подумать, - это добавить customSave, используя @Modifying с собственным запросом, но это будет последним средством.

Примечание: я должен использовать метку времени БД, точность очень важна, строки должны бытьсохраняется в порядке с возрастающими временными метками и смещениями времени сервера, вводящими условия гонки.

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

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

0 голосов
/ 30 мая 2018

Учитывая ваш список требований, у вас реально есть 3 варианта

  1. Использование триггера базы данных на вашей таблице для управления значениями отметки времени обновления.
  2. Использование обратного вызова @PreUpdate.
  3. Делайте это как часть службы, когда у вас есть доступ к состоянию обновления и существующему состоянию.

Опция (1) довольно проста, поскольку у вас есть и текущее состояниеи обновлять состояние в триггере базы данных, и вы можете выполнять любые необходимые операции, чтобы определить, следует ли вам установить значение или принять существующее значение на момент обновления.

Единственным недостатком (1) и (2) является то, что (2) не будет зависеть от времени базы данных, а скорее от времени приложения, потому что вы будете делать это в приложениисервер.Но (2) имеет то преимущество, что ваш код для этого будет независимым от базы данных, что позволит вам развернуть его в любом месте на любой платформе базы данных, которая поддерживает Hibernate или имеет функционирующий диалект без каких-либо проблем.

Мое личное мнение, выберите (2), потому что он также довольно сфокусирован на доменном дизайне.

Для реализации (2) это довольно просто

@Entity
public class YourSuperDumperEntity {

  // Clear this value on load
  @PostLoad
  public void postLoadClearFlags() {
    fieldValuesChangedThatRequireTimestampUpdate = false;
  }

  // This handles the setting of the value at update-time
  @PreUpdate
  public void preUpdateCallbackAdjustTimestampOnChanges() {
    if ( fieldValuesChangedThatRequireTimestampUpdate ) {
      updateTimestamp = new Date();
    }
  }


  public void setSomeFieldThatTriggersUpdateTimestamp(String value) {
    // check if the old and new value differ enough to trigger update date
    // if so, set the boolean flag here as follows
    this.fieldValuesChangedThatRequireTimestampUpdate = true;

    // now set the value
    this.someFieldThatTriggersUpdateTimestamp = value;
  }
}

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

Возможно, вам придется немного поиграть с обратными вызовами JPA, чтобы удовлетворить ваши потребности, но идея остается прежней.

Если вам не нравится (2), я бы предложил (3), потому что это поддерживает независимую от базы данных поддержку, которую я считаю гораздо более важной, чем отметка времени, полученная из самой базы данных.При правильной синхронизации времени операционной системы фактический источник времени не должен иметь значения.

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