Я хочу, чтобы 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