我在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>
我该如何解决我的问题?
我试图用相同的时区运行这两个应用程序。在这种情况下,一切都按预期工作。
我试图使用MySQL驱动程序6.0.6版本但它没有改变任何东西。
如果你在Java中使用LocalDate
,你应该在MySQL中使用DATE
列。这样问题就解决了。
如果你使用LocalDateTime
,尝试在Spring Boot中设置如下属性:
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
有关更详细的说明,请查看this article。你可以在我的High-Performance Java Persistence GitHub repository找到一个测试用例,效果很好。
我在使用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
}
这也应该解决你的问题。你可以收集更多信息here。
原因
我猜您的问题(检索日期 - 1天)来自您的具体设置。如果您的应用程序以UTC格式运行并从GMT + 3中的数据库请求时间戳,则它会在较早的日期解析,因为应用程序上下文(JVM
和Hibernate
在这里负责)比UTC中的数据库上下文落后3小时。简单的例子:
2018-12-02 00:00:00
- 3小时= 2018-12-01 21:00:00
因为你只是期待日期:qazxsw poi - 3小时= qazxsw poi
2018-12-02
当你使用TimeZoned Date时会使用它,但是从你的日志中你似乎没有传递TimeZone:
绑定参数[1]为[日期] - [2018-09-06]
尝试远程属性:
2018-12-01
理想情况下,您的两台服务器应位于相同的时区,并且首选的服务器应位于UTC时区。并在他的时区显示用户的正确时间;你在浏览器本身解析它。从DB中检索数据时;你使用UTC时间。这样,从DB获取数据时就不会有问题
在MySQL中......
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
在内部存储UTC,但根据两个设置转换为服务器的时区。通过spring.jpa.properties.hibernate.jdbc.time_zone=UTC
检查这些设置正确配置,阅读器可能会看到与编写器不同的时间(基于tz设置)。
TIMESTAMP
和SHOW VARIABLES LIKE '%zone%';
接受你提供的任何东西。客户端中的字符串与表中存储的内容之间没有tz转换。可以把它想象成一个存储时钟的图片。读者将看到作者写的同一时间字符串。
如果将以下解析添加到HQL查询中,它将返回没有任何时区格式或时间的日期。这是您的问题的快速解决方法。
DATE