Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Java/Kotlin插入的H2和MySQL数据库中的DATETIME值不匹配_Java_Mysql_Datetime_Kotlin_H2 - Fatal编程技术网

从Java/Kotlin插入的H2和MySQL数据库中的DATETIME值不匹配

从Java/Kotlin插入的H2和MySQL数据库中的DATETIME值不匹配,java,mysql,datetime,kotlin,h2,Java,Mysql,Datetime,Kotlin,H2,TLDR: 如何始终使用Java Hibernate将正确的UTC日期时间值保存到H2和MySQL数据库的日期时间类型字段中 完整上下文: 我在数据库中有一个带有DATETIME字段的表,我想在其中插入行: 默认情况下(未给出值时)将存储在当前UTC时间 或者,如果给定了UTC日期时间,则应将其存储在不带 额外的时区转换 问题是它必须在本地H2数据库、Docker内部的本地mysql和外部AWS RDS mysql实例上运行 我很难在所有3个实例中正确保存datetime 到目前为止,要么本

TLDR:

如何始终使用Java Hibernate将正确的UTC日期时间值保存到H2和MySQL数据库的日期时间类型字段中

完整上下文:

我在数据库中有一个带有DATETIME字段的表,我想在其中插入行:

  • 默认情况下(未给出值时)将存储在当前UTC时间
  • 或者,如果给定了UTC日期时间,则应将其存储在不带 额外的时区转换
问题是它必须在本地H2数据库、Docker内部的本地mysql和外部AWS RDS mysql实例上运行

我很难在所有3个实例中正确保存datetime

到目前为止,要么本地和aws mysql实例得到了正确的值,但本地H2得到了错误的值,要么反过来,当本地H2得到了正确的值,但mysql实例得到了错误的值

下面是我所拥有的kotlin代码的简短片段

Docker和AWS中适用于H2但不适用于MySQL的代码:

Docker和AWS中适用于MySQL但不适用于H2的代码:

它运行于:Spring Boot 2.1.3Hibernate Core 5.3.7MySQL 8.0.13H2 1.4.197

我在网上和stackoverflow上看到了很多问题,但不幸的是,没有一个解决方案可以解决我的问题

更新

在使用多种方法进行额外调试之后,通过查看Hibernate、H2和MySQL的日志,看起来UTC时间在H2和MySQL之间的处理方式完全相反

保存到本地H2:

  • [错误]使用
    Date
    ,当UTC为09:55时,Hibernate记录值“Fri Mar 2910:55:09 CET 2019”,它保存为“2019-03-2910:55:09.412”
  • [错误]使用
    Instant
    ,当UTC为16:48时,Hibernate记录值“2019-03-2816:48:18.270Z”,它保存为“2019-03-2817:48:18.27”
  • [错误]使用
    OffsetDateTime
    ,当UTC为10:11时,Hibernate记录值“2019-03-29T10:11:30.672Z”,保存为“2019-03-2911:11:30.672”
  • [正确]使用
    LocalDateTime
    ,当UTC为16:50时,Hibernate记录值“2019-03-28T16:50:20.697”,保存为“2019-03-2816:50:20.697”
在本地docker中保存到MySQL:

  • [正确]使用
    Date
    ,当UTC为09:51时,Hibernate记录值“Fri Mar 2910:51:56 CET 2019”,它保存为“2019-03-2909:51:56.519”
  • [正确]使用
    Instant
    ,当UTC为09:38时,Hibernate记录值“2019-03-29T09:38:59.172Z”,它保存为“2019-03-2909:38:59.172”
  • [正确]使用
    OffsetDateTime
    ,当UTC为10:14时,Hibernate记录值“2019-03-29T10:14:22.658Z”,它保存为“2019-03-2910:14:22.658”
  • [错误]使用
    LocalDateTime
    ,当UTC为16:57时,Hibernate记录值“2019-03-28T16:57:35.631”,保存为“2019-03-2815:57:35.631”

看来修复方法是为JDBC连接(而不是JVM)设置UTC时区:

它依赖于使用
Instant
在Java端保留值,并在MySQL和H2中使用
created_at
字段创建日期时间类型

缩短后的kotlin代码为:

@Entity
data class SomeEntity(
    val createdAt: Instant = Instant.now() // default created date is current UTC time
)

val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss")

createdAt = LocalDateTime.parse("2012-11-30 16:13:21", dateTimeFormatter).toInstant(ZoneOffset.UTC)
摘自《约普·艾根》评论和文章的观点

奖金

我想如果您正在阅读本文,您可能还需要帮助调试SQL查询

1。要打印在H2上运行的SQL查询,请将
跟踪级别\u文件=2
跟踪级别\u系统\u输出=2
添加到连接字符串(请参阅):

2.要启用休眠日志:

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type=TRACE
3.要在MySQL中启用查询日志(其中一种方法,不要在生产数据库上使用!):


将其与SQL
CURRENT_TIMESTAMP()
(h2+mysql)进行比较,以查看时间是否遵循相同的时钟。@joop eggen hm,时间戳不同。在本地H2上,当前_时间戳为
2019-03-28 16:04:29.434
,在本地Docker和AWS RDS MySQL节点上,当前_时间戳为
2019-03-28 15:04:29
。作为参考,当前本地时间为
2019-03-28 16:04:29
,当前UTC时间为
2019-03-28 15:04:29
。我不确定这是否是问题的根源,如果是,是否有办法解决?因此一台服务器在UTC上运行,一台在本地时间运行。我确实找到了关键词:数据库时区。顺便说一句,新的java时间类有我的偏好。@joop eggen是的,我多次偶然发现这个问题,但是为JVM设置UTC时区并没有解决这个问题。无论如何,这感觉是一个相当肮脏的方法。人们希望能够使用
CURRENT\u TIMESTAMP()
几乎等于
now()
,因此数据库应该是可配置的。也许吧。如果你发现了什么,请回答自己;因为那是沃思威尔。
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
@Entity
data class SomeEntity(
    val createdAt: Instant = Instant.now() // default created date is current UTC time
)

val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss")

createdAt = LocalDateTime.parse("2012-11-30 16:13:21", dateTimeFormatter).toInstant(ZoneOffset.UTC)
spring.datasource.url=jdbc:h2:mem:dbname;TRACE_LEVEL_FILE=2;TRACE_LEVEL_SYSTEM_OUT=2;
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type=TRACE
SET GLOBAL general_log = 'ON';
SET global log_output = 'table';
select * from mysql.general_log ORDER BY event_time DESC;