13 mysql date/time/datetime/year 的数据存储

news2025/1/23 7:07:36

前言

这里主要是 由于之前的一个 datetime 存储的时间 导致的问题的衍生出来的探究 

探究的主要内容为 int 类类型的存储, 浮点类类型的存储, char 类类型的存储, blob 类类型的存储, enum/json/set/bit 类类型的存储 

本文主要 的相关内容是 datetime/date/time/year 类类型的相关数据的存储  

这部分数据 客户端 和 服务器这边的交互 主要是以字符串的形式交互 

服务器这边的存储 将日期编码为 整形进行存储 

 

最近碰到了一个这样的一个问题

主要是在一个 增量同步的地方, 增量同步 tableA, 增量查询字段为 create_time, 类型为 datetime

然后 业务组件中 select max(create_time) from tableA 中查询到的最大时间 居然比实际的最大时间 多了 13 个小时, 呵呵

然后 这就导致了 增量同步存在问题

下一次增量同步的时候, 将 增量同步的最大值更新为了 13个小时以后, 这样 根据这个时间去做增量查询 接下来的 13 个小时的任务执行 都查询不到 需要增量同步的记录

然后 最终是发现 服务器的 default-time-zone 被调整了, 重置一下 default-time-zone 即可 

我这里 mysql 服务器版本为 5.7.31

 

 

mysql 中 datetime 的数据交互

创建表 以及插入测试数据

CREATE TABLE `tz_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `field1` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `test`.`tz_test`(`id`, `field1`) VALUES (1, '2023-04-24 16:25:40');

 

测试脚本如下 

package com.hx.test07;

/**
 * Test06MysqlTimezone
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2023/4/24 16:26
 */
public class Test06MysqlTimezone {

    // Test06MysqlTimezone
    public static void main(String[] args) {

        String url = "jdbc:mysql://10.60.50.16:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&autoReconnectForPools=true&useSSL=false";
        String username = "root";
        String password = "root";
        JdbcTemplate jdbcTemplate = Test14GenExpertSql.getMysqlJdbcTemplate(url, username, password);

        String sql = " select * from tz_test; ";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        int x = 0;


    }

}

 

抓包拿到 mysql 响应解析如下 

可见这里 wireshark 解析貌似是存在问题的, 前两个 packet 对应的是 字段列表的元数据 

第三个 packet 是具体的数据, 包含了 packetLength, packetNumber, 字段id, 字段field1

第四个 packet 是 eof 包 

6e2fe246a7f54cdfbf94b9c80d88cbe3.png

 

业务查询从服务器拿到的数据部分的如下, 可以看到的是 和上面一致

可以看到的是 datetime 的交互是通过字符串的形式交互的, 因此 存取的时候的转换都是服务器自己处理的

第一个字节 01 表示 id 数据长度 1 

第二个字节 31 表示 id 为 1

第三个字节 13 表示 field1 数据长度 19

剩余十九个字节为 “2023-04-24 16:25:40”

dafa944c1509418e89b896f7c37eadff.png

 

再看一下 insert into 存放数据的时候的相关 包的情况

整个 sql 语句是通过字符串的形式 交互给 mysql, mysql 自行解析 处理

0fc6a991a61d47fd9d8d01f8f968b71a.png

 

 

所以 客户端这边拿到的 datetime 的字符串 取决于服务器的时区配置, 以及客户端请求的时区配置 

我们这边调整一下 客户端这边的 serverTimezone 的配置, 整个 url 更新成为

jdbc:mysql://10.60.50.16:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&autoReconnectForPools=true&useSSL=false&serverTimezone=GMT%2B2

 

查看一下 服务器响应的数据

服务器相应的依旧是字符串的 “2023-04-24 16:25:40”

所以说这个 serverTimeZone 的转换是在客户端这边 

4e5138b1ce484106b08682f75d851c7f.png

 

客户端这边具体的时间转换是在这里, 服务器响应回来的时间是 “2023-04-24 16:25:40”

按照 GMT+2 的时间转换为时间戳为 “1682346340906”

换算成 我们 GMT+8 的时间为 “2023-04-24 22:25:40”

d0589e27c7cb41a4b3463c572ee1df68.png

 

具体获取时区的地方, 是从 session 的 serverTimeZone 获取的, 也就是我们上面指定的 serverTimeZone

efa3073838554fe4bbd3c2a308d6ec9e.png 

业务这边查询, 拿到的是时间戳为 “1682346340906”

然后按照 GMT+8 转换一下 “2023-04-24 22:25:40”

2dc21b19895447429a3188256169d67a.png

 

 

 调整 mysql 的 default_time_zone

--default_time_zone='+02:00'

增加默认时区的配置, 然后 再来查看一下 情况

服务器这边 响应回来的数据, 依然是 “2023-04-24 16:25:40”

22fe62b36a42400590e9b0cb50ed2390.png

 

然后客户端这边 按照 GMT+2 转换为时间戳

所以说 这里 serverTimeZone 可能取自两个地方, 一个是服务器, 一个是客户端 

ceae95e1ab4f45828836c546b4f2e2a0.png

 

可以看到这里 拿到的 field1 结果也是 

GMT+2 的 “2023-04-24 16:25:40”

GMT+8 的 “2023-04-24 22:25:40”

5d132794f2cb4364beea0241b8dfc7af.png

 

我们来看一下这里 获取 serverTimeZone 的地方 

优先获取的是 客户端配置的 timeZone

其次获取的是服务器的 timeZone, 有两种配置方式 

80e2c12de1034155bacb7e9e2c08eac2.png

 

服务器这边的变量是用如下 sql 查询的, 并注册到 serverVariables 中 

8018e302d60e432e847fe1419bb69d84.png 

查询的 sql 如下 

SELECT  @@session.auto_increment_increment AS auto_increment_increment, @@character_set_client AS character_set_client, @@character_set_connection AS character_set_connection, @@character_set_results AS character_set_results, @@character_set_server AS character_set_server, @@collation_server AS collation_server, @@collation_connection AS collation_connection, @@init_connect AS init_connect, @@interactive_timeout AS interactive_timeout, @@license AS license, @@lower_case_table_names AS lower_case_table_names, @@max_allowed_packet AS max_allowed_packet, @@net_write_timeout AS net_write_timeout, @@performance_schema AS performance_schema, @@query_cache_size AS query_cache_size, @@query_cache_type AS query_cache_type, @@sql_mode AS sql_mode, @@system_time_zone AS system_time_zone, @@time_zone AS time_zone, @@transaction_isolation AS transaction_isolation, @@wait_timeout AS wait_timeout

63f12e6a02c84a9ca16ca8b9f78f974a.png

 

 

与客户端的交互, 获取给定的 datetime 的编码之后的 longlong 表示 

然后再 解码为目标格式 的字符串表示

cff79e3a68cf410d9589a4be7ef39b99.png

 

格式化的模板为 yyyy-MM-dd HH:mm:ss

a9f5d75dcaa94f20ae3e6006299e7a0a.png

 

 

mysql 服务器 datetime 的数据存储 

然后 我们来看一下 mysql 这边 datetime 字段的存储, 测试语句如下

客户端交互 字符串过去, 服务端拿到 这个字符串会做什么处理呢?

insert into tz_zone (field1) values ('2023-04-24 16:25:40');

 

首先如下地方是 将字符串转换为 MYSQL_TIME 的结构体, 处理就是解析出 年月日, 时分秒 等等信息 放到 MYSQL_TIME 中

bbb91bdd50154b2eb4f1cb6e66e35187.png

 

解析之后 MYSQL_TIME 中存储了传入 时间所表示的 年月日, 时分秒 等等信息

11ac378230ed46349e5e92235efeadde.png 

这是具体的存储方案, 将 MYSQL_TIME 编码成为一个 longlong

存储方案 在备注中 解释的很明确

/*
    1 bit  sign            (used when on disk)
   17 bits year*13+month   (year 0-9999, month 0-12)
    5 bits day             (0-31)
    5 bits hour            (0-23)
    6 bits minute          (0-59)
    6 bits second          (0-59)
   24 bits microseconds    (0-999999)

   Total: 64 bits = 8 bytes

   SYYYYYYY.YYYYYYYY.YYdddddh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff
*/

 13662b3fbc2e47d0ac80790cf2d420eb.png

 

 

然后 响应就是一个逆向的过程

首先 还原成 MYSQL_TIME

然后 再转换成为字符串

整个过程中可以理解为 对于时间字符串的 编码, 解码

抽象这个编码解码的过程, 可以理解为 服务器这边 存放 datetime 就是存放的一个字符串, 所以说 服务器这边 datetime的存放是不涉及时区的

28308994974f4d6c89f5ba945639b1b4.png

 

 

mysql 中 date/time/year 的机制和 datetime 类似 

com.mysql.cj.result 相关实体是将协议的 字节序列 转换为 具体的基础数据类型的数据

 

date

4f82c88026324af1a2f03752b6363951.png

 

time

c72646e5cc954311a176ff6bf3bb5213.png 

 year

1cc77ae2c15e4759bc7e02ec928730ec.png

 

timestamp

1bd3f7e1d8aa467bad98f50873936c14.png

 

 

date 的格式化 

c2fc5482b45e48abad4c58c9bf7a3ca0.png

 

 

 year 的格式化

abe0a39050b04a87a6b617594625a689.png

 

 


 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/962938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RNN 单元:分析 GRU 方程与 LSTM,以及何时选择 RNN 而不是变压器

一、说明 深度学习往往感觉像是在雪山上找到自己的道路。拥有坚实的原则会让你对做出决定更有信心。我们都去过那里 在上一篇文章中&#xff0c;我们彻底介绍并检查了 LSTM 单元的各个方面。有人可能会争辩说&#xff0c;RNN方法已经过时了&#xff0c;研究它们是没有意义的。的…

如何增强客户支持?用全渠道聊天机器人

您的用户在哪里&#xff1f;您是否想拥有源源不断的客户&#xff1f;全渠道聊天机器人可确保您在他们需要的地方为他们提供一致的客户支持&#xff01; 自技术出现以来&#xff0c;消费者行为已经完全改变。这意味着企业与用户互动和提供客户支持的方式也发生了变化。现在&…

Spring 系统架构

Spring总共大约有 20个模块&#xff0c;由1300多个不同的文件构成。而这些组件被分别整合在核心容器&#xff08;CoreContainer&#xff09;、AOP&#xff08;Aspect Oriented Programming&#xff09;和设备支持&#xff08;Instrmentation&#xff09;、数据访问及集成&#…

文心一言放出的“时代礼物”,藏着中国科技的黄金机会

8月31日&#xff0c;第一批国产大模型通过了“生成式人工智能备案”&#xff0c;可以开放公众服务。 一石激起千层浪&#xff0c;对AIGC强烈好奇&#xff0c;为国产应用疯狂打call&#xff0c;文心一言对话刷屏朋友圈&#xff0c;普通人和科技圈都嗨翻了。 不到24小时&#xff…

硬件SPI口扩展

在工控板设计中&#xff0c;经常会遇到扩展IO。具有相同的功能电路板接口相同&#xff0c;所以很容易采用排线方式连接到CPU主控板上&#xff0c;这种排线连接&#xff0c;我称之为总线。 现在的CPU引脚多&#xff0c;不扩展IO&#xff0c;使用模拟SPI&#xff0c;也可以实现&…

【力扣每日一题】2023.9.2 最多可以摧毁的敌人城堡数量

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这道题难在阅读理解&#xff0c;题目看得我匪夷所思&#xff0c;错了好多个测试用例才明白题目说的是什么。 我简单翻译一下就是寻找1和…

15000字、6个代码案例、5个原理图让你彻底搞懂Synchronized

Synchronized 本篇文章将围绕synchronized关键字&#xff0c;使用大量图片、案例深入浅出的描述CAS、synchronized Java层面和C层面的实现、锁升级的原理、源码等 大概观看时间17分钟 可以带着几个问题去查看本文&#xff0c;如果认真看完&#xff0c;问题都会迎刃而解&…

03_nodjs_npm的使用

03 【npm的使用】 1.包和npm 1.1 什么是包 由于 Node 是一套轻内核的平台&#xff0c;虽然提供了一系列的内置模块&#xff0c;但是不足以满足开发者的需求&#xff0c;于是乎出现了包&#xff08;package&#xff09;的概念&#xff1a; 与核心模块类似&#xff0c;就是将一…

[学习笔记]斜率优化dp 总结

前言&#xff1a; 我们学过不少优化类的算法了&#xff0c;大部分都是基于凸函数的性质给出的优化&#xff0c;比如Slope Trick&#xff0c;Wqs二分&#xff0c;又比如今天的斜率优化&#xff08;不知道什么时候会有空把Slope Trick写掉&#xff09; 正文&#xff1a; 我们考…

这个在线网站让你三分钟制作出一份精美简历

今天&#xff0c;我要向大家推荐一个神奇的在线工具网站&#xff0c;它能够提供免费简历模板、简历范文&#xff0c;支持在线编辑&#xff0c;并且一键下载为PDF。这个工具让你的简历制作变得轻松便捷&#xff01; 首先&#xff0c;这个网站的简历模板非常丰富多样。无论你是刚…

bazel构建原理

调度模型 传统构建系统有很多是基于任务的&#xff0c;例如 Ant&#xff0c;Maven&#xff0c;Gradle。用户可以自定义"任务"(Task&#xff09;&#xff0c;例如执行一段 shell 脚本。用户配置它们的依赖关系&#xff0c;构建系统则按照顺序调度。 基于 Task 的调度…

揭秘亚马逊Amazon测评,掌握细节和技巧,提升产品销量和评论数量

亚马逊是全球最大的跨境电商平台&#xff0c;拥有全球65个国家的几十个网站。对于跨境卖家来说&#xff0c;亚马逊是最值得选择的平台之一。 亚马逊的八大站点分别是美国、加拿大、墨西哥、欧洲、澳大利亚、日本、中东和巴西。 美国站点是全球最大的零售市场&#xff0c;拥有…

区块链实验室(18) - 用FISCO BCOS架设1个无标度网络

FISCO技术文档提供1个4节点的网络案例&#xff0c;这4个节点构成1个强连通图。强连通图在现实中通常是不存在的。 本文用FISCO架设1个网络&#xff0c;该网络由100个节点构成1个无标度(scale free)网络&#xff0c;如下图所示。 1 用FISCO工具构建1个100节点的初始网络 FISCO提…

Jenkins java8安装版本安装

一、首先准备Jenkins、Jdk8、Tomcat9安装包 根据Jenkins官网介绍&#xff0c;Jenkins支持Java8的版本如下&#xff1a; 我们选择2.164版本进行安装&#xff0c;根据版本号支持输入下载地址&#xff1a;https://archives.jenkins.io/war/2.164/jenkins.war&#xff0c;进行下载…

【牛客网题目】合并两个排序的链表

目录 描述 题目分析 描述 输入两个递增的链表&#xff0c;单个链表的长度为n&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 数据范围&#xff1a;0≤n≤1000&#xff0c;1000≤节点值≤1000 要求&#xff1a;空间复杂度 O(1)&#xff0c;时间复杂…

为什么我说 90% 的技术人搞副业都会失败?!

见字如面&#xff0c;我是军哥&#xff01; 这几天有多位程序员读者请教我&#xff0c;如何搞副业&#xff1f;并且有一位已经搞了半年了&#xff0c;涨粉困难&#xff0c;这小伙子大概工作 2 年的样子&#xff0c;所在的公司算中等二线大厂吧。 我把和他们聊的内容总结了一下&…

vscode调教配置:快捷修复和格式化代码

配置vscode快捷键&#xff0c;让你像使用idea一样使用vscode&#xff0c;我们最常用的两个功能就是格式化代码和快捷修复&#xff0c;所以这里修改一下快捷修复和格式化代码的快捷键。 在设置中&#xff0c;找到快捷键配置&#xff1a; 然后搜索&#xff1a;快捷修复 在快捷键…

分库分表篇-1 分库分表介绍

文章目录 前言一、为什么要分库分表&#xff1f;二、分库分表的策略&#xff1a;2.1 垂直切分&#xff1a;2.2.1 垂直分库&#xff1a;2.2.2 垂直分表&#xff1a;2.2.3 垂直拆分的优缺点: 2.2 水平切分&#xff1a;2.2.1 库内分表:2.2.2 分库分表:2.2.3 水平切分优缺点: 三、分…

04-MySQL02

1、什么是索引下推&#xff1f; 索引下推&#xff08;index condition pushdown &#xff09;简称ICP&#xff0c;在Mysql5.6的版本上推出&#xff0c;用于优化查询。 需求: 查询users表中 "名字第一个字是张&#xff0c;年龄为10岁的所有记录"。 SELECT * FROM u…

无涯教程-JavaScript - FTEST函数

FTEST函数取代了Excel 2010中的F.TEST函数。 描述 该函数返回F检验的输出。 F检验返回两尾概率,即array1和array2的方差没有显着差异。使用此功能可以确定两个样本是否具有不同的方差。 语法 FTEST (array1, array2)争论 Argument描述Required/OptionalArray1The first ar…