Hibernate сохраняет / извлекает дату минус день, если приложение использует другой часовой пояс, чем MySQL - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть приложение, запущенное на tomcat на MACHINE_A с часовым поясом GMT + 3.

Я использую удаленный сервер MySQL, запущенный на MACHINE_B с часовым поясом UTC.

Мы используем spring-data-jpa для настойчивости.

В качестве примера проблемы я покажу репозиторий:

public interface MyRepository extends JpaRepository<MyInstance, Long> {
    Optional<MyInstance> findByDate(LocalDate localDate);
}

Если я передам localDate для 2018-09-06, я получу сущности с датой 2018-09-05 (предыдущий день)

В логах вижу:

2018-09-06 18:17:27.783 TRACE 13676 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [DATE] - [2018-09-06]

Я много гуглил этот вопрос и нашел несколько статей с одинаковым содержанием (например, https://moelholm.com/2016/11/09/spring-boot-controlling-timezones-with-hibernate/)

Итак, у меня есть следующее application.yml:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/MYDB?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC
    username: root
    password: *****
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    properties:
      hibernate:
        show_sql: true
        use_sql_comments: true
        format_sql: true
        type: trace
        jdbc:
          time_zone: UTC

Но это не помогает.

Мы используем следующий разъем:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.12</version>
</dependency>

Как мне решить мою проблему?

приписка

Я пытался запустить оба приложения в одном часовом поясе. В этом случае все работает как положено.

P.S.2

Я пытался использовать версию драйвера MySQL 6.0.6, но это ничего не меняет.

Ответы [ 6 ]

0 голосов
/ 11 октября 2018

Если вы добавите следующий разбор к вашему HQL-запросу, он вернет дату без какого-либо формата часового пояса или времени суток. Это быстрый способ решения вашей проблемы.

select DATE_FORMAT(date,'%Y-%m-%d') from Entity
0 голосов
/ 08 октября 2018

spring.jpa.properties.hibernate.jdbc.time_zone=UTC

Используется, когда вы работаете с TimeZone Date, но из ваших логов кажется, что вы не передаете TimeZone:

параметр привязки [1] как [ДАТА] - [2018-09-06]

Попробуйте удаленное свойство:

spring.jpa.properties.hibernate.jdbc.time_zone=UTC

0 голосов
/ 15 сентября 2018

Я столкнулся с похожими проблемами при создании некоторых интеграционных тестов для приложения spring-boot с использованием hibernate. База данных, которую я здесь использовал, была postgreSQL.

Как правильно показывает другой ответ, вы можете установить свойство hibernate.jdbc.time_zone=UTC как описанное. Но это не помогло решить мои проблемы, поэтому мне пришлось установить часовой пояс по умолчанию JVM с помощью следующего в моем spring-boot основном классе приложений:

@PostConstruct
public void init(){
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));   // It will set UTC timezone
    System.out.println("Spring boot application running in UTC timezone :"+new Date());   // It will print UTC timezone
}

Это также должно решить ваши проблемы. Вы можете собрать больше информации здесь .

Причина

Полагаю, ваша проблема (дата получения - 1 день) связана с вашей конкретной настройкой. Если ваше приложение работает в UTC и запрашивает метки времени из базы данных в GMT + 3, оно разрешается в более раннюю дату, поскольку контекст приложений (здесь ответственны JVM и Hibernate) на 3 часа отстает от контекста базы данных в UTC. Простой пример:

2018-12-02 00:00:00 - 3 часа = 2018-12-01 21:00:00

Поскольку вы смотрите только на даты: 2018-12-02 - 3 часа = 2018-12-01

0 голосов
/ 12 сентября 2018

В MySQL ...

TIMESTAMP внутренне хранит UTC, но преобразует в / из часового пояса сервера на основе двух настроек. Проверьте эти настройки с помощью SHOW VARIABLES LIKE '%zone%'; При правильной настройке считыватель может увидеть другое время, чем записывающее устройство (в зависимости от настроек tz).

DATE и DATETIME возьмите все, что вы дадите. Там нет преобразования tz между строкой в ​​клиенте и тем, что хранится в таблице. Подумайте об этом, храня картину часов. Читатель увидит ту же строку времени, которую написал писатель.

0 голосов
/ 09 сентября 2018

В идеале оба ваших сервера должны находиться в одном часовом поясе, а предпочтительнее - в часовом поясе UTC.И показывать правильное время пользователю в его часовом поясе;Вы анализируете это в самом браузере.И при получении данных из БД;Вы используете время UTC.Таким образом, у вас не будет проблем при получении данных из БД

0 голосов
/ 06 сентября 2018

Если вы используете LocalDate в Java, вы должны использовать DATE столбец в MySQL. Таким образом, проблема будет решена.

Если вы используете LocalDateTime, попробуйте установить следующее свойство в Spring Boot:

spring.jpa.properties.hibernate.jdbc.time_zone=UTC

Для более подробного объяснения, посмотрите эту статью . Вы можете найти тестовый пример в моем высокопроизводительном хранилище Java Persistence GitHub , которое прекрасно работает.

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