我在MACHINE_A的tomcat上启动了一个具有时区GMT + 3的应用程序。
我使用时区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版本,但它没有任何改变。
答案 0 :(得分:11)
如果在Java中使用LocalDate
,则应在MySQL中使用DATE
列。这样就可以解决问题。
如果您使用LocalDateTime
,请尝试在Spring Boot中这样设置属性:
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
有关详细说明,请查看this article。您可以在我的High-Performance Java Persistence GitHub repository中找到一个很好的测试用例。
答案 1 :(得分:2)
在使用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
在此处负责)比数据库晚了3个小时。 UTC中的上下文。简单的例子:
2018-12-02 00:00:00
-3小时= 2018-12-01 21:00:00
仅查看日期:2018-12-02
-3hours = 2018-12-01
答案 2 :(得分:2)
版本8.0.22之前的MySQL连接器中存在一个错误,请参见Spring data query for localdate returns wrong entries - minus one day
答案 3 :(得分:1)
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
在您使用“时区日期”时会用到它,但是从您的日志中看,您似乎没有通过“时区”:
将参数[1]绑定为[DATE]-[2018-09-06]
尝试访问媒体资源:
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
答案 4 :(得分:0)
理想情况下,您的两台服务器应位于同一时区,首选服务器应位于UTC时区。并向用户显示其所在时区的正确时间;您可以在浏览器本身中对其进行解析。并且在从数据库检索数据时;您使用UTC时间。这样,从数据库中获取数据时就不会有问题
答案 5 :(得分:0)
在MySQL中...
TIMESTAMP
在内部存储UTC,但基于两个设置在服务器时区之间进行转换。通过SHOW VARIABLES LIKE '%zone%';
检查这些设置。正确配置后,阅读器可能会看到与写入器不同的时间(基于tz设置)。
DATE
和DATETIME
随您便。客户端中的字符串与表中存储的字符串之间没有tz转换。可以认为它是存储时钟的图片。读者将看到作者编写的相同时间字符串。
答案 6 :(得分:0)
如果将以下解析添加到HQL查询,它将返回没有任何时区格式或一天中的时间的日期。这是解决问题的快速解决方案。
select DATE_FORMAT(date,'%Y-%m-%d') from Entity
答案 7 :(得分:0)
我已经按照之前的答案进行了所有操作,例如
TimeZone.setDefault(TimeZone.getTimeZone("America/Sao_Paulo"))
但是它们都不起作用,直到我在JDBC URL中添加参数 serverTimezone = America / Sao_Paulo 为止:
jdbc:mysql://localhost:3306/aurorabuzz-test?serverTimezone=America/Sao_Paulo
现在一切正常!