如果应用程序使用另一个时区而不是MySQL,则Hibernate会保存/检索日期减去日期

问题描述 投票:14回答:6

我在MACHINE_A上使用时区GMT + 3在tomcat上启动了一个应用程序。

我使用带有时区UTC的MACHINE_B上启动的远程MySQL服务器。

我们使用spring-data-jpa来表示持久性。

作为问题的一个例子,我将展示存储库:

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

如果我为2018-09-06传递localDate,我会得到日期为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版本但它没有改变任何东西。

java mysql hibernate spring-boot timezone
6个回答
11
投票

如果你在Java中使用LocalDate,你应该在MySQL中使用DATE列。这样问题就解决了。

如果你使用LocalDateTime,尝试在Spring Boot中设置如下属性:

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

有关更详细的说明,请查看this article。你可以在我的High-Performance Java Persistence GitHub repository找到一个测试用例,效果很好。


2
投票

我在使用spring-boothibernate应用程序创建一些集成测试时遇到了类似的问题。我在这里使用的数据库是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
}

这也应该解决你的问题。你可以收集更多信息here

原因

我猜您的问题(检索日期 - 1天)来自您的具体设置。如果您的应用程序以UTC格式运行并从GMT + 3中的数据库请求时间戳,则它会在较早的日期解析,因为应用程序上下文(JVMHibernate在这里负责)比UTC中的数据库上下文落后3小时。简单的例子:

2018-12-02 00:00:00 - 3小时= 2018-12-01 21:00:00

因为你只是期待日期:qazxsw poi - 3小时= qazxsw poi


1
投票

2018-12-02

当你使用TimeZoned Date时会使用它,但是从你的日志中你似乎没有传递TimeZone:

绑定参数[1]为[日期] - [2018-09-06]

尝试远程属性:

2018-12-01


0
投票

理想情况下,您的两台服务器应位于相同的时区,并且首选的服务器应位于UTC时区。并在他的时区显示用户的正确时间;你在浏览器本身解析它。从DB中检索数据时;你使用UTC时间。这样,从DB获取数据时就不会有问题


0
投票

在MySQL中......

spring.jpa.properties.hibernate.jdbc.time_zone=UTC在内部存储UTC,但根据两个设置转换为服务器的时区。通过spring.jpa.properties.hibernate.jdbc.time_zone=UTC检查这些设置正确配置,阅读器可能会看到与编写器不同的时间(基于tz设置)。

TIMESTAMPSHOW VARIABLES LIKE '%zone%';接受你提供的任何东西。客户端中的字符串与表中存储的内容之间没有tz转换。可以把它想象成一个存储时钟的图片。读者将看到作者写的同一时间字符串。


0
投票

如果将以下解析添加到HQL查询中,它将返回没有任何时区格式或时间的日期。这是您的问题的快速解决方法。

DATE
© www.soinside.com 2019 - 2024. All rights reserved.