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>
問題を解決するにはどうすればよいですか?
同じタイムゾーンで両方のアプリケーションを実行しようとしました。この場合、すべてが期待どおりに機能します。
MySQLドライバー6.0.6バージョンを使用しようとしましたが、何も変わりません。
JavaでLocalDate
を使用している場合、MySQLでDATE
列を使用する必要があります。この方法で問題は解決されます。
LocalDateTime
を使用する場合は、Spring Bootで次のようにプロパティを設定してください。
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
より詳細な説明については、 この記事 をご覧ください。私の High-Performance Java Persistence GitHubリポジトリ でテストケースを見つけることができます。
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
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
MySQLで...
TIMESTAMP
は内部的にUTCを保存しますが、2つの設定に基づいてサーバーのタイムゾーンとの間で変換します。 SHOW VARIABLES LIKE '%zone%';
を介してこれらの設定を確認してください。正しく構成されている場合、リーダーはライターとは異なる時間を見ることがあります(tz設定に基づく)。
DATE
とDATETIME
は、あなたが与えたものを何でも取ります。クライアントの文字列とテーブルに保存されている文字列の間には、tz変換はありません。時計の写真を保存すると考えてください。リーダーには、ライターが書いたsame時間文字列が表示されます。
理想的には、両方のサーバーが同じタイムゾーンにあり、優先されるサーバーはUTCタイムゾーンであることが望ましいです。そして、タイムゾーンでユーザーに正しい時間を表示します。ブラウザ自体で解析します。また、DBからデータを取得します。 UTC時間を使用します。この方法では、DBからデータを取得する際に問題は発生しません
HQLクエリに次の解析を追加すると、タイムゾーン形式や時刻を指定せずに日付が返されます。これは問題の簡単な回避策です。
select DATE_FORMAT(date,'%Y-%m-%d') from Entity