从Java/Kotlin插入的H2和MySQL数据库中的DATETIME值不匹配
TLDR: 如何始终使用Java Hibernate将正确的UTC日期时间值保存到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 到目前为止,要么本
- 默认情况下(未给出值时)将存储在当前UTC时间
- 或者,如果给定了UTC日期时间,则应将其存储在不带 额外的时区转换
- [错误]使用
,当UTC为09:55时,Hibernate记录值“Fri Mar 2910:55:09 CET 2019”,它保存为“2019-03-2910:55:09.412”Date
- [错误]使用
,当UTC为16:48时,Hibernate记录值“2019-03-2816:48:18.270Z”,它保存为“2019-03-2817:48:18.27”Instant
- [错误]使用
,当UTC为10:11时,Hibernate记录值“2019-03-29T10:11:30.672Z”,保存为“2019-03-2911:11:30.672”OffsetDateTime
- [正确]使用
,当UTC为16:50时,Hibernate记录值“2019-03-28T16:50:20.697”,保存为“2019-03-2816:50:20.697”LocalDateTime
- [正确]使用
,当UTC为09:51时,Hibernate记录值“Fri Mar 2910:51:56 CET 2019”,它保存为“2019-03-2909:51:56.519”Date
- [正确]使用
,当UTC为09:38时,Hibernate记录值“2019-03-29T09:38:59.172Z”,它保存为“2019-03-2909:38:59.172”Instant
- [正确]使用
,当UTC为10:14时,Hibernate记录值“2019-03-29T10:14:22.658Z”,它保存为“2019-03-2910:14:22.658”OffsetDateTime
- [错误]使用
,当UTC为16:57时,Hibernate记录值“2019-03-28T16:57:35.631”,保存为“2019-03-2815:57:35.631”LocalDateTime
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;