在实体中设置日期字段时,我遇到了与hibernate相关的奇怪问题。 日期在java程序中被解释为UTC(我做了一个System.out以确保分配的日期是'UTC'。但是,当hibernate实际上持续存储到数据库时,日期将转换为本地时间并存储) 恩。该值已在实体设置器中设置为“2009-09-09 00:08:08” - GMT 持续到数据库的实际值是“2009-09-08 08:08:08” - 美国东部时间。 我无法找出发生的地点和原因以及如何防止它。感谢
P.S。我正在使用joda日期库并注释该字段 @ org.hibernate.annotations.Type(type =“org.joda.time.contrib.hibernate.PersistentDateTime”)
答案 0 :(得分:3)
但是,当hibernate实际上持久存储到数据库时,日期将转换为本地时间并存储)ex。该值已在实体设置器中设置为“2009-09-09 00:08:08” - GMT持续到数据库的实际值为“2009-09-08 08:08:08” - 美国东部时间。< / p>
好的,首先,无论您使用哪种列类型在MySQL中存储日期(TIMESTAMP或DATETIME),都不存储时区。来自Re: Storing timezone with datetime:
TIMESTAMP是自1970年以来的秒数,占4个字节。它存储在GMT中。也就是说,TZ偏移量在您存储值时应用,然后在您获取时重新应用。 (...)
DATETIME是一个8字节的数字字符串“yyyymmddhhmmss”。 (...)
第二,除非buggy behavior,我的理解是转换应该由服务器或JDBC驱动程序完成,具体取决于the server time zone设置,这样就不会出现不一致数据
在这两种情况下,我的观点是存储“2009-09-09 00:08:08” - GMT 或“2009-09-08 08:08:08” - 美国东部时间 来自Java 应该在数据库中产生相同的值。
但是,当显示时,看起来会进行不同的转换。这引出了一个问题:你是如何实际检查“持久日期”的值的。 SQL客户端中是否出现“问题”?在Java代码中?
DateTime的MySQL文档说“MySQL以'YYYY-MM-DD HH:MM:SS'格式检索并显示DATETIME值”。这意味着mysql将“自纪元以来的毫秒”转换为上述格式。所以现在我的问题是,时区信息也存储在mysql中吗?
我已经更新了我的初步答案(这不完全准确/详尽)。无论您使用的是DATETIME还是TIMESTAMP,答案都是否定的。
我做的另一个观察是,只有当我在Java应用程序中设置日期时,上述日期“转换”问题才存在。如果我使用'UTC_TIMESTAMP()'创建一个mysql触发器来更新/设置日期,则日期将显示在'UTC'时间内。
UTC_TIMESTAMP()函数始终会返回当前的 UTC 日期和时间。
我想知道的是:
答案 1 :(得分:1)
为了在数据库中将日期视为UTC(用于读/写),您可以使用这个小型开源库DbAssist
。它使用自定义UtcDateType
来映射实体中的java.util.Date
字段,以便它们在数据库中被Hibernate视为UTC。由于您使用的是JPA注释,因此您将使用以下依赖项:
<dependency>
<groupId>com.montrosesoftware</groupId>
<artifactId>DbAssist-5.2.2</artifactId>
<version>1.0-RELEASE</version>
</dependency>
应用此修复很容易,例如,使用Spring Boot时,您必须确保在应用程序类之前有@EnableAutoConfiguration
注释。如果您使用的是其他Hibernate版本,请参阅github wiki以找到正确版本的修补程序和安装指南。您还可以在此article中详细了解时区转换问题。
答案 2 :(得分:0)
Joda Time Contrib的这种行为在我的项目Usertype for Joda Time和JSR310中得到修复。请参阅http://usertype.sourceforge.net/,这实际上是JodaTime Hibernate的替代品。
我已经写过关于这个问题:http://blog.jadira.co.uk/blog/2010/5/1/javasqldate-types-and-the-offsetting-problem.html
希望这有帮助,
克里斯