• mysql时间类型与时区


    mysql用来存储日期时间的数据类型有两种:DATETIME和TIMESTAMP。

    DATETIME类型,可认为存储的是日期时间文本,如 2022-02-19 21:26:35。它不是一个完整的时间,因为它未指明时区,从而也无法定位到现实中确定的时间点。

    TIMESTAMP类型,其存储的是时间戳,即保存了从1970年1月1日0点整(格林尼治标准时间)以来的秒数。它是一个完整的时间,可以代表现实中的某个时间点。

    由此可知,DATETIME类型其存储结构决定了,其无法代表现实中具体的时间点。那怎么办呢?我们只需对以DATETIME类型存储的 日期时间文本 指定一个时区,即可明确表示现实中的某个时间点。如,日期时间文本 ‘2022-02-19 21:26:35’,我们指定其为东八区,则这个时间点就是完整的了。在mysql中,我们通过指定数据库的时区,来实现上述操作。
    mysql的时区,可以在数据库服务中设置默认值确定,也可以在连接会话中指定,且每个会话对时区的指定只在当前会话有效。因此,在一个mysql的连接会话中,可认为其时区由连接方决定。

    由上所述,我们得到3个关键点:
    (1)DATETIME类型存储的是日期时间文本
    (2)TIMESTAMP类型存储的是时间戳
    (3)mysql的时区可由数据库连接方指定

    * 问题场景

    在涉及到这两种数据类型的java程序中,我们经常遇到两个问题场景:
    (1)jvm从mysql取出的日期时间数据,在到浏览器前端后,浏览器处看到的显示文本,与mysql中有小时偏差。
    (2)前端输入的日期时间文本,在到mysql后,看到的显示文本,与前端输入有小时偏差。

    * 问题分析

    一个普通的java应用,根据数据的流经路径,会有3个区域:mysql数据库、jvm、brower浏览器。这3个区域的时区设置,未必一致,这就导致了一个同样的时间点,在3处环境的显示不一致。此外,时间类型的数据,在3处流转时,若不以完整时间点的形式来流转,这也导致了3处的时间不一致。

    • TIMESTAMP


    如前所述,timestamp类型存储的是时间戳,它能代表一个完整的时间点。mysql--jvm--brower之间若以标准的时间戳的形式进行交互,不会有歧义,但是显示的文本随时区会有差异,但这属于正常现象。
    但以日期时间文本的形式,且不带时区的形式,会造成混淆。如brower与jvm之间以时间文本的形式交互,则再与mysql交互时,会把该时间文本,默认指定为jvm的时区,造成混淆,违背了用户的本意。

    • DATETIME


    DATETIME类型不是完整的时间点,但jdbc默认会把它映射为一个完整的时间类型,即java.sql.Timestamp。在映射过程中,jdbc给DATETIME类型的数据指定了一个时区,从而使其成为一个完整的时间点。时区的指定,是在jdbc与mysql的连接会话中指定的,指定方式详见附文。
    所指定时区,可能与jvm和brower所在时区都不一致,导致java.sql.Timestamp类型在jvm中转化为本地时间后,即LocalDatetime,其文本值与原始数据库中的文本值不一致。而浏览器端得到的时间文本,又直接是jvm中的本地时间文本,从而在整个操作中,潜意识地将浏览器的时区设置成了和jvm一致,导致数据的处理的混淆和错误。

    *最佳实践


    回归到事务的本质,即 DATETIME类型存储的是日期时间文本,TIMESTAMP存储的是时间戳。因此建议:


    1 TIMESTAMP类型:mysql--jvm–brower之间都以时间戳的形式交互,前端根据本身所在时区进行文本显示的转换。


    2 DATETIME类型:类型本身不是一个完整的时间,但jdbc与mysql交互时,会在连接会话中给mysql指定时区,再根据jvm时区和所指定的mysql时区,作文本显示值的转换,并将转换后的值传给mysql。因此,为了避免引起混淆,前后端交互时,也应该以完整时间点的形式进行交互,即 “时间文本+时区” 的格式,如,“2021-08-12T10:52:32+08:00 ”。且时区最好为连接会话中所指定的时区。这样就保证了前端看到的时间文本与mysql中一致,且时区转换也不会引起混淆。

    * 名称解释

    (1)完整时间点

    可表示现实中的某个时间点,本文中有两种形式:a 日期时间文本+时区,b 时间戳

    (2)mysql时区

    在一个连接会话中,mysql的时区决定于3个配置:a. 会话中的时区配置(jdbc连接字符串中的serverTimezone),b. mysql默认全局时区,c. 操作系统时区。且优先级为 a>b>c。

  • 相关阅读:
    「Wallace 笔记」K-D tree 区域查询时间复杂度简易证明
    「LOJ #2980」「THUSCH 2017」大魔法师
    「Wallace 笔记」快速上手回文自动机(PAM)
    「ZJU Summer Training 2020
    「AtCoder AGC002F」Leftmost Ball
    文案高手的18项修炼
    高性能MySQL实战
    300分钟搞懂 Spring Cloud
    腾讯产品启示录
    300分钟吃透分布式缓存
  • 原文地址:https://www.cnblogs.com/yyg1986/p/15920374.html
Copyright © 2020-2023  润新知