web-dev-qa-db-ja.com

アプリケーションがMySQL以外のタイムゾーンを使用する場合、Hibernateは日付から日を引いた日付を保存/取得します

MACHINE_AのTomcatでタイムゾーンGMT + 3で起動したアプリケーションがあります。

私はタイムゾーンUTCでMACHINE_Bで開始されたリモートMySQLサーバーを使用します。

永続化のために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バージョンを使用しようとしましたが、何も変わりません。

14
gstackoverflow

JavaでLocalDateを使用している場合、MySQLでDATE列を使用する必要があります。この方法で問題は解決されます。

LocalDateTimeを使用する場合は、Spring Bootで次のようにプロパティを設定してください。

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

より詳細な説明については、 この記事 をご覧ください。私の High-Performance Java Persistence GitHubリポジトリ でテストケースを見つけることができます。

11
Vlad Mihalcea

hibernateを使用してspring-bootアプリケーションの統合テストを作成しているときに、同様の問題に直面しました。ここで使用したデータベースはpostgreSQLでした。

別の答えが正しく指摘しているように、hibernate.jdbc.time_zone=UTCプロパティをdiscribedのように設定できます。これで問題が解決しなかったので、spring-bootアプリケーションのメインクラスで次の助けを借りてJVMデフォルトタイムゾーンを設定する必要がありました。

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

これも問題を解決するはずです。より多くの情報を収集できます here

理由

問題(取得日-1日)は、特定のセットアップに起因していると思います。アプリケーションがUTCで実行され、GMT + 3のデータベースにタイムスタンプを要求する場合、アプリケーションコンテキスト(JVMおよびHibernateがここで責任を負う)が3時間遅れているため、以前の日付で解決されます。 UTCのデータベースコンテキスト。簡単な例:

2018-12-02 00:00:00-3時間= 2018-12-01 21:00:00

日付のみを探している場合:2018-12-02-3hours = 2018-12-01

2
git-flo

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

TimeZoned Dateを操作しているときに使用されますが、ログからTimeZoneを渡していないようです:

バインディングパラメータ[1] as [DATE]-[2018-09-06]

プロパティをリモートにしよう:

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

1
ValerioMC

MySQLで...

TIMESTAMPは内部的にUTCを保存しますが、2つの設定に基づいてサーバーのタイムゾーンとの間で変換します。 SHOW VARIABLES LIKE '%zone%';を介してこれらの設定を確認してください。正しく構成されている場合、リーダーはライターとは異なる時間を見ることがあります(tz設定に基づく)。

DATEDATETIMEは、あなたが与えたものを何でも取ります。クライアントの文字列とテーブルに保存されている文字列の間には、tz変換はありません。時計の写真を保存すると考えてください。リーダーには、ライターが書いたsame時間文字列が表示されます。

0
Rick James

理想的には、両方のサーバーが同じタイムゾーンにあり、優先されるサーバーはUTCタイムゾーンであることが望ましいです。そして、タイムゾーンでユーザーに正しい時間を表示します。ブラウザ自体で解析します。また、DBからデータを取得します。 UTC時間を使用します。この方法では、DBからデータを取得する際に問題は発生しません

0
Pavan

HQLクエリに次の解析を追加すると、タイムゾーン形式や時刻を指定せずに日付が返されます。これは問題の簡単な回避策です。

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