wake-up-neo.com

Hibernate speichert Datum/Tag, wenn die Anwendung eine andere Zeitzone als MySQL verwendet

Ich habe eine Anwendung auf Tomcat auf MACHINE_A mit der Zeitzone GMT + 3 gestartet.

Ich verwende einen Remote-MySQL-Server, der auf MACHINE_B mit der Zeitzone UTC gestartet wurde.

Wir verwenden spring-data-jpa für die Persistenz.

Als Beispiel für das Problem zeige ich das Repository:

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

Wenn ich localDate für 2018-09-06 übergeben habe, erhalte ich Entitäten, bei denen das Datum 2018-09-05 (am Vortag) ist.

In den Protokollen sehe ich: 

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]

Ich habe diese Frage viel gegoogelt und mehrere Artikel mit gleichem Inhalt gefunden (zum Beispiel https://moelholm.com/2016/11/09/spring-boot-controlling-timezones-with-hibernate/ )

Ich habe also den folgenden 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

Aber es hilft nicht.

Wir verwenden den folgenden Konnektor:

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

Wie kann ich mein Problem lösen?

P.S.

Ich habe versucht, beide Anwendungen mit derselben Zeitzone auszuführen. In diesem Fall funktioniert alles wie erwartet.

P.S.2

Ich habe versucht, die Version des MySQL-Treibers 6.0.6 zu verwenden, aber es ändert sich nichts.

13
gstackoverflow

Wenn Sie LocalDate in Java verwenden, sollten Sie in MySQL eine DATE-Spalte verwenden. Auf diese Weise wird das Problem gelöst.

Wenn Sie LocalDateTime verwenden, versuchen Sie, die Eigenschaft in Spring Boot so einzustellen:

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

Eine ausführlichere Erklärung finden Sie unter diesem Artikel . Einen Testfall finden Sie in meinem High Performance Java Persistence GitHub-Repository , der gut funktioniert.

11
Vlad Mihalcea

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

Es wird verwendet, wenn Sie mit TimeZoned Date arbeiten, aber in Ihren Protokollen scheint es, als würden Sie TimeZone nicht passieren:

bindungsparameter [1] als [DATE] - [2018-09-06]

Versuchen Sie, die Immobilie zu entfernen:

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

1
ValerioMC

Bei der Erstellung einiger Integrationstests für eine spring-boot-Anwendung mit hibernate bin ich ähnlichen Problemen begegnet. Die Datenbank, die ich hier verwendete, war postgreSQL.

Wie eine andere Antwort richtig hervorhebt, können Sie die hibernate.jdbc.time_zone=UTC-Eigenschaft wie beschrieben einstellen. Nichtsdestotrotz löste dies meine Probleme nicht. Daher musste ich die JVM-Standardzeitzone mithilfe der folgenden Informationen in meiner spring-boot-Anwendungshauptklasse festlegen:

@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
}

Dies sollte auch Ihre Probleme lösen. Weitere Informationen erhalten Sie hier

Grund

Ich schätze, Ihr Problem (Abrufdatum - 1 Tag) kommt von Ihrem spezifischen Setup. Wenn Ihre Anwendung in UTC ausgeführt wird und Zeitstempel von einer Datenbank in GMT + 3 anfordert, wird sie zu einem früheren Zeitpunkt aufgelöst, da der Anwendungskontext (hier JVM und Hibernate) in UTC 3 Stunden hinter dem Datenbankkontext liegt. Einfaches Beispiel:

2018-12-02 00:00:00 - 3hours = 2018-12-01 21:00:00

Da Sie nur auf die Daten schauen: 2018-12-02 - 3hours = 2018-12-01

1
git-flo

In MySQL ...

TIMESTAMP speichert intern UTC, konvertiert jedoch in/aus der Zeitzone des Servers basierend auf zwei Einstellungen. Überprüfen Sie diese Einstellungen über SHOW VARIABLES LIKE '%zone%';. Bei richtiger Konfiguration kann der Leser eine andere Zeit als der Schreiber sehen (basierend auf den tz-Einstellungen).

DATE und DATETIME nehmen, was immer Sie geben. Es gibt keine tz-Konvertierung zwischen der Zeichenfolge im Client und der in der Tabelle gespeicherten. Denken Sie daran, ein Bild einer Uhr zu speichern. Der Leser wird die gleiche Zeitzeichenfolge sehen, die der Schreiber geschrieben hat.

0
Rick James

Im Idealfall sollten sich beide Server in derselben Zeitzone und bevorzugt in der UTC-Zeitzone befinden. Und um dem Benutzer die korrekte Zeit in seiner Zeitzone anzuzeigen; Sie parsen es im Browser selbst. Und während Daten von DB abgerufen werden; Sie verwenden die UTC-Zeit. Auf diese Weise haben Sie beim Abrufen von Daten aus der DB kein Problem

0
Pavan

Wenn Sie der HQL-Abfrage das folgende Parsing hinzufügen, wird ein Datum ohne Zeitzonenformat oder Tageszeit zurückgegeben. Dies ist eine schnelle Lösung für Ihr Problem.

select DATE_FORMAT(date,'%Y-%m-%d') from Entity
0
Alain Cruz