Задать столбец метки времени JPA для создания базы данных? - PullRequest
52 голосов
/ 01 мая 2009

В моей базе данных SQL Server 2000 у меня есть столбец отметки времени (в функции, не в типе данных) типа DATETIME с именем lastTouched, установленным на getdate() в качестве значения по умолчанию / привязки.

Я использую сгенерированные классы сущностей JPA Netbeans 6.5, и у меня это есть в коде

@Basic(optional = false)
@Column(name = "LastTouched")
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;

Однако, когда я пытаюсь поместить объект в полученную базу данных,

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched

Я попытался установить для @Basic значение (optional = true), но возникает исключение, в котором говорится, что база данных не допускает значения null для столбца TIMESTAMP, чего нет в конструкции.

ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.

Ранее я использовал это для работы в чистом Hibernate, но у меня есть смысл переключиться на JPA и не знаю, как сказать, что этот столбец предполагается генерировать на стороне базы данных. Обратите внимание, что я по-прежнему использую Hibernate в качестве слоя сохранения JPA.

Ответы [ 6 ]

50 голосов
/ 01 мая 2009

Я исправил проблему, изменив код на

@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;

Таким образом, столбец метки времени игнорируется при генерации вставок SQL. Не уверен, что это лучший способ сделать это. Обратная связь приветствуется.

35 голосов
/ 24 июня 2010

Я понимаю, что это немного поздно, но я успешно аннотировал столбец отметки времени с помощью

@Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

Это также должно работать с CURRENT_DATE и CURRENT_TIME. Я использую JPA / Hibernate с Oracle, поэтому YMMV.

6 голосов
/ 29 декабря 2017
@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;

это сработало для меня. подробнее

4 голосов
/ 15 февраля 2016

Я не думаю, что у каждой базы данных есть метки времени автообновления (например, Postgres). Поэтому я решил обновить это поле вручную везде в моем коде. Это будет работать с каждой базой данных:

thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);

Есть причины использовать триггеры, но для большинства проектов это не один из них. Триггеры еще глубже погружают вас в конкретную реализацию базы данных.

MySQL 5.6 .28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66), кажется, очень простителен, не требуя ничего, кроме

@Column(name="LastTouched")

MySQL 5.7 .9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) работает только с

@Column(name="LastTouched", insertable=false, updatable=false)

не

FAILED: removing @Temporal
FAILED: @Column(name="LastTouched", nullable=true)
FAILED: @Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")

Моя другая системная информация (одинаковая в обеих средах)

  • hibernate-entitymanager 5.0.2
  • Спящий-валидатор 5.2.2
  • mysql-connector-java 5.1.38
4 голосов
/ 28 апреля 2011

У меня это хорошо работает с использованием JPA2.0 и MySQL 5.5.10, для случаев, когда меня волнует только последний раз, когда строка была изменена. MySQL создаст отметку времени при первой вставке, и каждый раз при вызове UPDATE в строке. (ПРИМЕЧАНИЕ: это будет проблематично, если мне будет интересно, действительно ли ОБНОВЛЕНИЕ внесло изменения).

Столбец "отметка времени" в этом примере похож на столбец "последний раз коснулся". X`

Приведенный ниже код использует отдельный столбец «версия» для оптимистической блокировки.

private long version;
private Date timeStamp

@Version
public long getVersion() {
    return version;
}

public void setVersion(long version) {
    this.version = version;
}

// columnDefinition could simply be = "TIMESTAMP", as the other settings are the MySQL default
@Column(name="timeStamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
@Temporal(TemporalType.TIMESTAMP)
public Date getTimeStamp() {
    return timeStamp;
}

public void setTimeStamp(Date timeStamp) {
    this.timeStamp = timeStamp;
}

(ПРИМЕЧАНИЕ: @Version не работает в столбце MySQL «DATETIME», где тип атрибута «Дата» в классе Entity. Это произошло потому, что Date генерировал значение с точностью до миллисекунды, однако MySQL не был сохраняя миллисекунду, поэтому, когда он сравнивал то, что было в базе данных, и «присоединенную» сущность, он думал, что у них разные номера версий)

Из руководства MySQL относительно TIMESTAMP :

With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
0 голосов
/ 17 июня 2019
@Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
@Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`
...