2017-02-19 19 views
13

У меня есть эти два классаКопирование ТШЕЗТАМР к DATETIME на MySQL с Hibernate

class Source { 
    // mapped to TIMESTAMP 
    @Version 
    @Column(columnDefinition="TIMESTAMP(3) DEFAULT '2016-01-01'") 
    Instant myInstant; 
} 

class Destination { 
    // mapped to DATETIME 
    @Basic(optional=true) 
    Instant myInstant; 
} 

При использовании Hibernate, я назначить

destination.myInstant = source.myInstant; 

, а затем сохраненное значение меньше на один час, чем оригинал - как в соответствии с командной строкой MySQL-клиента, так и на Java. Мой часовой пояс - UTC + 1, поэтому причина, очевидно, заключается в преобразовании часового пояса.

Есть несколько мест, где это можно исправить, но я ищу наилучшую практику. Сервер должен работать по всему миру, поэтому он должен продолжать использовать UTC внутренне, не так ли?

Должен ли я просто изменить тип столбца на TIMESTAMP? Тогда почему Instant по умолчанию - DATETIME?


Согласно this article, Instantделает карту к TIMESTAMP, но в моем случае это не так. Зачем?

+0

Предоставьте 'SHOW CREATE TABLE' и SQL, сгенерированный из Hibernate. –

+0

@RickJames Там ничего интересного нет: 'SHOW CREATE TABLE' показывает типы типа' timestamp (3) NOT NULL DEFAULT '2016-01-01 01: 00: 00.000' и ​​'datetime'. Заявления - это просто выбор и обновление, без логики. Значения не регистрировались. Я бы опубликовал журнал в любом случае, но мне пришлось бы заменить имена реальных классов и полей теми, которые использовались в моем вопросе, и это не стоит того, поскольку там действительно ничего нет. – maaartinus

+0

'SHOW VARIABLES LIKE '% zone%';' –

ответ

1

В MySQL 5 & значения TIMESTAMP преобразуются из текущего часового пояса в UTC для хранения и преобразуются обратно из UTC в текущий часовой пояс для извлечения. Это происходит только для типа данных TIMESTAMP, но не для DATETIME. Именно по этой причине вы видите разницу при назначении TIMESTAMP для DATETIME. Итак, нужно иметь обе колонки одного типа. Hibernate по умолчанию отображает InstantType в базу данных типа TIMESTAMP. Хотя вы можете использовать его как для TIMESTAMP, так и для DATETIME в MYSQL, они обрабатываются по-разному.

5

Если вы хотите работать с часовыми поясами и Java 8, я бы рекомендовал использовать ZonedDateTime или OffsetTimeZone (последний предпочитается при работе с Hibernate). Для более старых версий используйте Calendar.

  • Когда вы экземпляр, он должен идти по умолчанию с часовым поясом вашего компьютера.
  • Проверьте, соответствует ли база данных временной отметке с часовым поясом или без него.
  • Установленный по умолчанию параметр также не имеет часовой пояс, и если он «с часовым поясом», он должен автоматически добавлять смещение базы данных.

Надеюсь, что-то из этого работает. Вот как я это сделал в одном из моих проектов.

@Column(name = "registration_time") 
private OffsetDateTime registrationTime; 
[...] 
subscriber.setRegistrationTime(OffsetDateTime.now()); 
+0

Я не совсем доволен вашим ответом, но это не ваша вина. Мне придется больше исследовать, что происходит на самом деле (см. Мой ответ Рику Джеймсу). – maaartinus