Я хочу, чтобы Hibernate сохранял свойства LocalDateTime в базе данных H2 с точностью, содержащей наносекунды (Timestamp(9)) по умолчанию.
«По умолчанию» означает, что прикрепление @Column(columnDefinition = "TIMESTAMP(9)") к каждому свойству LocalDateTime не может быть решением.
В Hibernate5 решением было создать собственный диалект и вызвать registerColumnType(Types.TIMESTAMP, "timestamp(9)") в его конструкторе.
Однако я не нашел решения для Hibernate6. Я попытался создать собственный диалект и переопределить его resolveSqlTypeLength.
public class CustomH2Dialect extends H2Dialect {
/* The Hibernate 5 Solution was to call registerColumnType(Types.TIMESTAMP, "timestamp(9)"); in the ctor.*/
@Override
public int resolveSqlTypeLength(String columnTypeName, int jdbcTypeCode, int precision, int scale,
int displaySize) {
if (jdbcTypeCode == Types.TIMESTAMP) {
return 9;
}
return super.resolveSqlTypeLength(columnTypeName, jdbcTypeCode, precision, scale, displaySize);
}
}
Но похоже, что метод не вызывается.
Есть ли у кого-нибудь идеи: как настроить TIMESTAMP(9) для всех временных меток (LocalDateTime...) по умолчанию? Репозиторий Git для тестов можно найти: https://gitlab.com/RalphEng/experiment-hibernate6-h2-datetime
Предыстория: вариант использования — Spring Tests. Запускаю Spring и память H2 для теста. И у меня есть много тестов, которые содержат такие тесты, как:
MyEntity myEntity = new MyEntity ();
myEntity.timestamp = LocalDateTime.now();
myEntity.xzy = ....
entityManager.persist(myEntity);
entityManager.flush();
entityManager.clear();
MyEntity reloaded = entityManager.find(MyEntity .class, myEntity.getId());
assertThat(reloaded.timestamp).isEqualsTo(myEntity.timestamp)
//otherFieldsTo
Честно говоря, тесты в большинстве случаев не такие простые, и проверка того, что временная метка точно такая же, на самом деле не предназначена и не нужна. Но я не могу это исправить. Так что повышение точности — это всего лишь способ проведения тестов.
И поскольку это только «проблема» в тестах, я не могу добавить @Column(columnDefinition = "TIMESTAMP(9)"), потому что это также изменит поведение производства.
@AndrzejWięcławski, ты не можешь хранить это в long - оно не поместится. Вот почему Instant приходится рассматривать нано отдельно
Вы уверены, что хотите LocalDateTime? Если вы отслеживаете определенные точки на временной шкале, это неправильный класс.
Вы понимаете, что аппаратные часы обычных компьютерных часов не могут отслеживать дату и время с точностью до наносекунд? Они делают это за микросекунды.




Решение Hibernate6 состоит в том, чтобы использовать собственный диалект и переопределить метод getDefaultTimestampPrecision для возврата 9:
public class CustomH2Dialect extends H2Dialect {
@Override
public int getDefaultTimestampPrecision() {
return 9;
}
}
Извините, но где? github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src/… <- Я не могу найти ни одного getDefaultTimestampPrecision метода :/
@vampYr09 - спасибо, но: //миллисекунды или микросекунды — это максимум //для большинства диалектов, поддерживающих явную //точность, за исключением Oracle, //который принимает до 9 цифр, и DB2, //который принимает до 12 цифр!
Возможно, самый простой способ — сохранить временную метку как длинную (наносекунды), до
GMT: Friday, 11 April 2262 23:47:16.854