当前位置: 首页 > 知识库问答 >
问题:

为什么在JDBC连接字符串中指定的时区会影响瞬时在MySQL中的存储方式?

党宇定
2023-03-14

在我们的项目(Spring Boot 2.2.3、MySQL 5.7、Hibernate、Java14)中,所有与日期相关的字段都是datatypeJava.time.instant。在我们的MySQL中,所有字段的类型都是datetime

IntelliJ中表视图中时间的显示似乎不受我设置的serverTimeZone的影响,所以我希望它显示存储在DB中的普通值。

当我将JDBC连接的connectionString更改为JDBC:mysql:/localhost/mydb?Characterencoding=utf-8&UselegacyDateTimeCode=false&ServerTimeZone=utc并且我的实体中的值为2020-07-13T00:00:00z时,数据库中的2020-07-13T00:00:00z将被持久化(通过IntelliJ/DataGrip查看)。当我使用JDBC连接再次阅读它时,我使用2020-07-13T00:00:00Z正确地接收到它。

所以看起来我有一个瞬间,Java/MySQL假设它是UTC,并将它转换为connectionstring中指定的时区,因此为我的时区添加了冬季时间的1小时/夏季时间的2小时。

我想了解的是谁执行这些时区调整以及为什么。因为我从MySQL文档中了解到,对于类型datetime不应该进行这些调整。

MySQL将时间戳值从当前时区转换为UTC以进行存储,并将时间戳值从UTC转换回当前时区以进行检索。(对于其他类型(如DateTime)则不发生这种情况。)默认情况下,每个连接的当前时区是服务器的时间。时区可以在每个连接的基础上设置。只要时区设置保持不变,就会返回存储的相同值。如果存储一个时间戳值,然后更改时区并检索该值,则检索的值与您存储的值不同。

共有1个答案

姚俊材
2023-03-14

MySQL“datetime”存储符号、年、日、时、分、秒和小数秒。它相当于localdatetime

但是,您正在为它编写epoch millis(用新的time API术语:java.time.instant)。传统上,数据库中的datetime值被认为是基于即时的(例如,epoch millis而不是基于人类YMDhms的),因此java.sql.timestamp扩展了java.util.date(注意,j.u.date是一个赤裸裸的谎言,它表示epoch millis,而不是日期)。API也证明了这一点:J.U.Date中不推荐使用除提取/设置Epoch-Mill的方法之外的所有方法。

请注意,现代的JDBC规范实际上要求支持新的java.time类型,如localdate,我可以确认,例如用于postgres的JDBC驱动程序可以正确地实现这一点。

在过去,JDBC API会增长新的方法--例如,在PreparedStatement中有.setLocalTime(idxOfQuestionMark,localTimeInstance)方法,在ResultSet中有.getLocalTime(idxCoureOfColumn)。但是,不再。任何新添加的类型都要使用:

LocalTime lt = resultSet.getObject(idxOrNameOfColumn, LocalTime.class);
preparedStatement.setObject(paramIndex, lt);

要尝试做的第一件事是获得mysql存储数据的方式,以及java表示它从mysql获得的数据/发送到mysql的方式,以便对齐。因为如果MySQL db有一个YMDhms值,而您的java代码可以观察这个值的唯一方式是通过一个对象,该对象的内部存储允许它只表示Epoch-milli,那么,猜猜怎么着?某处有人正在进行基于时区的转换,因为如果没有时区,就无法从Epochmilis转换到YMDhms,反之亦然。如果您然后再转换回来,您只是引入了错误的机会。

但是,它是mysql,而mysql不是一个很好的数据库,所以上述方法很有可能不起作用(尽管JDBC规范或多或少地要求支持LocalTime、LocalDate、LocalDateTime和ZonedDateTime,而LDT与mysql的DATETIME列实际包含的内容非常匹配)。所以,如果这不起作用....

你将不得不绕着它跳舞,并且接受转换的发生。这将意味着您正在观察的内容(连接时区对您读取的内容有影响)将保持不变。一个解决方案是忘记DATETIME(毕竟,如果LDT实例确实不能发送到JDBC MySQL驱动程序/从JDBC MySQL驱动程序接收),那么您根本就没有办法可靠地设置或获取这样的列。重新设计您的DB定义,将TIMESTAMP与TIMEZONE一起使用(这就像ZonedDateTime,它与Instant(历元-毫秒)非常接近,因此转换不再是问题,尽管它仍然不是最佳的)。锁定两侧的区域,您就可以可靠地从epoch-millis转换到该区域和返回该区域。

或者,更好的是,找到一个更好的DB引擎:)

 类似资料:
  • 问题内容: 我在Java中使用过String,StringBuilder和StringBuffer。 当我从效率的角度思考时,我想到了这个问题。 字符串连接中使用“ +”会影响效率吗? 问题答案: 是的,但是在大多数情况下都没关系。 对字符串常量使用“ +”是最有效的方法,因为编译器可以执行串联操作。 如果要连接两个String,则该方法效率最高,因为它避免使用StringBuilder。 除了向

  • 问题内容: 我有下表 我需要将所有注释收集到单个字符串中 如果不订购,则按预期方式工作,最后返回所有您的注释。但是在运行以下代码后,添加了 ORDER BY 子句: 仅返回最后一条评论。有谁知道为什么ORDER BY导致串联的奇怪结果? PS:如果使用 FOR XML 子句代替串联,则可以很好地工作。是否有一种方法可以创建SQL Server函数,以将子查询中的多行“填充”到单个定界字段中? 问题

  • 问题内容: String a = “devender”; String b = “devender”; String c = “dev”; String d = “dev” + “ender”; String e = c + “ender”; a 和 b 都指向字符串常量池中的同一String Literal。所以在情况1 应该在内部使用类似- a 和 d 如何指向同一参考而不是 a & e ?

  • 因为Python的不能更改,我想知道如何更有效地连接字符串? 我可以这样写: 或者像这样: 在写这个问题的时候,我发现了一篇谈论这个话题的好文章。 http://www.skymind.com/~ocrow/python_string/ 但是它是在Python2.x中,所以问题是Python3中是否做了一些更改?

  • 问题内容: 我有几个服务器进程,它们有时会响应来自客户端的消息并执行只读事务。 在服务器运行大约几天后,它们停止正常工作,当我检查发现有大量有关关闭连接的消息时。 当我检查出它时,发现默认情况下,hibernate模式在某种开发模式下起作用,在这种模式下,几个小时后连接被断开,我开始使用c3po进行连接池。 但是,即使使用c3po,在启动服务器后约24小时仍会出现此问题。 有没有人遇到过这个问题,

  • 我的模拟模型中有在GIS空间漫游的代理。我建立了一个参数变化实验来产生复制。在运行期间,我收到了四条通知,“服务器没有响应。连接超时。”然而,模拟一直在运行,它仍然产生了结果。这个错误的影响是什么?为什么会这样? 我的路由是从开源地图服务器请求的,路由服务器选项是AnyLogic。