为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

当年话下 2022-09-07 17:35:39
如何使用Java Hibernate始终将正确的UTC日期时间值保存到H2和MySQL数据库的DATETIME类型字段中?完整上下文:我在数据库中有一个带有DATETIME字段的表,我想在其中插入行:默认情况下(未给出值时)将存储当前UTC时间或者,如果给定了 UTC 日期时间,则应在不进行其他时区转换的情况下存储该时间。它必须在本地H2数据库以及Docker内部的本地mysql和外部AWS RDS MySQL实例上运行的问题。而且我很难在所有3个实例中正确保存日期时间。到目前为止,本地和aws mysql实例要么获得正确的值,但本地H2获得错误的值,要么相反,当本地H2获得正确的值但MySQL实例获得错误的值时。以下是我拥有的kotlin代码的缩短片段。适用于 H2 但不适用于 Docker 和 AWS 中的 MySQL 的代码:@Entitydata class SomeEntity(    val createdAt: LocalDateTime = LocalDateTime.now(Clock.systemUTC())    // If createdAt is not explicitly given when saving new entry in db, the default value will be used    // and H2 will get correct value of '2019-03-28 12:36:56',    // but it will be wrong for MySQL, it will get '2019-03-28 11:36:56')val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss")createdAt = LocalDateTime.parse("2012-11-30 16:13:21", dateTimeFormatter)// In this case when createdAt is explicitly given when saving new entry in db,// H2 gets correct value '2012-11-30 16:13:21', // but MySQL DBs will get wrong value of '2012-11-30 17:13:21'适用于 Docker 和 AWS 中的 MySQL 但不适用于 H2 的代码:@Entitydata class SomeEntity(    val createdAt: Date = Date()    // If createdAt is not explicitly given when saving new entry in db, the default value will be used    // and MySQL DBs will get correct value of '2019-03-28 12:36:56'    // but it will be wrong for H2 as it will get '2019-03-28 13:36:56' (my current local time instead of UTC))val dateTimeFormatter = SimpleDateFormat("yyyy-MM-dd H:mm:ss")dateTimeFormatter.timeZone = TimeZone.getTimeZone("UTC")createdAt = dateTimeFormatter.parse("2012-11-30 16:13:21")// In this case when createdAt is explicitly given when saving new entry in db,// MySQL DBs will get correct value '2012-11-30 16:13:21', // but H2 will get wrong value of '2012-11-30 17:13:21'运行于:Spring Boot 2.1.3,Hibernate Core 5.3.7,MySQL 8.0.13,H2 1.4.197我在网上和stackoverflow上看到了一堆问题,但不幸的是,没有一个解决方案可以解决我的问题。
查看完整描述

1 回答

?
杨__羊羊

TA贡献1943条经验 获得超7个赞

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


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

它依赖于 use 将值保留在 Java 端,并在 MySQL 和 H2 中具有 DATETIME 类型的字段。Instantcreated_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)

想法取自“Joop Eggen”的评论,这个和这篇文章。


奖金


我想如果你正在阅读这篇文章,你可能还需要调试SQL查询的帮助。


1. 要打印在 H2 上运行的 SQL 查询,请添加和连接字符串(请参阅此处):TRACE_LEVEL_FILE=2TRACE_LEVEL_SYSTEM_OUT=2


spring.datasource.url=jdbc:h2:mem:dbname;TRACE_LEVEL_FILE=2;TRACE_LEVEL_SYSTEM_OUT=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 中启用查询日志(其中一种方法,请勿在生产数据库上使用!


SET GLOBAL general_log = 'ON';

SET global log_output = 'table';

select * from mysql.general_log ORDER BY event_time DESC;


查看完整回答
反对 回复 2022-09-07
  • 1 回答
  • 0 关注
  • 156 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信