【时区】Flink JDBC 和CDC时间字段时区 测试及时间基准

关联文章:
各种时间类型和timezone关系浅析

一、测试目的和值

1. 测试一般的数据库不含time zone的类型的时区。

  • mysql timestamp(3) 类型
  • postgres timestamp(3) 类型
  • sqlserver datetime2(3) 类型
  • oracle类型 TIMESTAMP(3) 类型
    在以下测试之中均为ts字段

2.测试CDC中元数据op_ts 时区

op_tsTIMESTAMP_LTZ(3) NOT NULL当前记录表在数据库中更新的时间。如果从表的快照而不是 binlog 读取记录,该值将始终为0。|

在以下测试中cdc表建表均使用ts_ms TIMESTAMP_LTZ(3) METADATA FROM 'op_ts' VIRTUAL 表示。
cdc在读取表时候分两个阶段:

  1. 全量读取阶段,特点是jdbc读取,读取数据中op=r
  2. 增量读取阶段,特点是log读取,读取数据中op=c或u或d
    op在截图中看到如3="r" 或者 3="r",3是op字段的索引值。
    ts_ms在全量阶段读取数据以下成为READ数据
    ts_ms在增量阶段读取数据以下成为CREATE数据

3. flink 数据时间表示和时区

flink Table中时间必须使用org.apache.flink.table.data.TimestampData对象表示。

@PublicEvolving  
public final class TimestampData implements Comparable<TimestampData> {  private final long millisecond;  private final int nanoOfMillisecond;
}

此类型使用如下两个值联合表示记录时间。并不记录时区数据。

实战测试:

@Test  
public void testTimeZone(){  // 常识:Epoch就是值utc的0时间点,是全局绝对时间点,本质是`ZoneOffset.of("+0")`下的0时间。与`January 1, 1970, 00:00:00 GMT`视为等同。  // GMT是前世界标准时,UTC是现世界标准时。UTC 比 GMT更精准,以原子时计时,适应现代社会的精确计时。  // 28800000=8*3600*1000。8小时毫秒值。  // 如下时间是+8时区的数据库存储的不带时区的时间:2023-09-28T09:43:20.320  long ts=1695894200320L;  // 如果将ts当做utc时间0时刻转为字符串则会导致时间+8 hour。2023-09-28 17:43:20。这是一般常用的在线转换时间的结果。因其默认是是epoch时间,所以转换后会+8h。  // 可见数据库读取的不带timezone时间的毫秒值,并不是以utc0时间(epoch)为基准的,而是以当前时区0为基准的。  // LocalDateTime对象本质支持LocalDate和LocalTime两个对象,LocalDate持有Integer的`年`,`月`,`日`。LocalTime则持有Integer的`时`,`分`,`秒`等和java.util.Date类型并不一样。  // LocalDateTime 的带有ZoneOffset方法比较难理解,此处:  // epochSecond 当然值的是epoch的秒数,是绝对时间概念和`java.util.Date.getTime()/1000`对应的,而offset是指此epoch秒数需要偏移的时间量。  // 内部代码是`long localSecond = epochSecond + offset.getTotalSeconds();`。  // 如下代码是正确的,因为java中的`java.util.Date`类和`java.sql.Timestamp`类型都是持有绝对时间的类,`Date.getTime`获得也是相对于Epoch的毫秒值(Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT)。  LocalDateTime ldtFromDate = LocalDateTime.ofEpochSecond(new Date().getTime() / 1000, 0, ZoneOffset.of("+8"));  System.out.println(ldtFromDate);  // 2023-09-28T16:16:45。此时时钟也是16:17:44。  Date date0 = new Date(0); // number of milliseconds since the standard base time known as "the epoch"  System.out.println(date0.getTime()); // 0, date0.getTime()方法返回绝对时间Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT  // 如下的提供`ZoneOffset.UTC`可以理解是告诉LocalDateTime我提供的epochSecond已是`localSecond=当地时间-当地时间的0点`不需要再做转换了。  LocalDateTime ldt0 = LocalDateTime.ofEpochSecond(0L, 0, ZoneOffset.UTC);  System.out.println(ldt0); // 1970-01-01T00:00  LocalDateTime ldt8 = LocalDateTime.ofEpochSecond(0L, 0, ZoneOffset.of("+8"));  System.out.println(ldt8); // 1970-01-01T08:00  // TimestampData 默认不会进行任何时区转换。也不存储任何时区信息。内部仅靠`long millisecond`和`int nanoOfMillisecond`存储信息,以便于序列化。  // millisecond 一般可以认为是本地时间。因其在toString方法中会不会进行时区转换,toString方法仅是调用了`toLocalDateTime()`,中进行简单运算,并最终调用`LocalDateTime.toString`方法。  TimestampData td0 = TimestampData.fromEpochMillis(0); // 相当于LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC)。  System.out.println(td0); // 1970-01-01T00:00。可见TimestampData输出转字符串的时间就是以utc时间为基准的这和java.util.Date类型是一致的。  LocalDateTime ldt = LocalDateTime.ofEpochSecond(  ts / 1000  , (int) (ts % 1000 * 1_000_000)  , ZoneOffset.UTC);  System.out.println(ldt); // 2023-09-28T09:43:20.320  TimestampData td = TimestampData.fromEpochMillis(ts);  System.out.println(td); // 2023-09-28T09:43:20.320  Date date = new Date(ts); // 注意:参数date(the specified number of milliseconds since the standard base time known as "the epoch")应该是epoch但此时ts并不是epoch基准的而是本地local基准的。  System.out.println(date); // Thu Sep 28 17:43:20 CST 2023,CST就是北京时间了,其在toString方法中`BaseCalendar.Date date = normalize();`进行了时区转换即+8了。  
}

4. 测试组件版本

  • flink 1.13
  • flink-cdc 2.2.1
  • flink-connector-jdbc 自己定制的,根据3.1.1-1.17版本修改而来。

二、本测试共测试四大数据库:

  • mysql
  • postgres
  • sqlserver
  • oracle

二、每种数据库测试8项:

  • database-SQL
    直接从数据中读取数据,是测试的基准值
  • cdc-RowData
    使用cdc的SQL API从数据库中读取值并在 com.ververica.cdc.debezium.table.AppendMetadataCollector#collect 方法中debug得到数据
  • cdc-SQL(测试除ts_ms的字段)
    使用cdc的SQL API读取值使用flink sql-client查询,用于测试除ts_ms的字段。因ts_ms准确性需分两种情况讨论。
  • cdc-SQL-RealTime(测试ts_ms)
    使用cdc的SQL API从读取值,左上角是系统时间,下侧是实时读取的数据。
  • cdc-Read数据(测试snapshot读取ts_ms字段)
    测试snapshot读取ts_ms字段,即全量读取阶段的ts_ms值,按照flink-cdc官方解释此四个数据的全量阶段值均为0(1970-01-01 00:00:00)。非0即为不正确。
  • cdc-Create数据(测试incremental读取ts_ms字段)
    测试incremental读取ts_ms字段,即增量读取阶段的ts_ms值。按照flink-cdc官方解释此四个数据的增量阶段值为数据日志记录时间。
  • jdbc-RowData
    使用flink SQL API 读取connector是jdbc的表数据org.apache.flink.connector.jdbc.table.JdbcRowDataInputFormat#nextRecord的方法中debug得到数据。。不含tm_ms数据。
  • jdbc-SQL
    使用flink SQL API 读取connector是jdbc的表数据。使用flink sql-client查询。。不含tm_ms数据。

三、测试过程数据

3.1 mysql

3.1.1 database-SQL

在这里插入图片描述

3.1.2 cdc-RowData

在这里插入图片描述

3.1.3 cdc-SQL(测试除ts_ms的字段)

![[image-20230927163847043.png|201]]

3.1.4 cdc-SQL-RealTime(测试ts_ms)

如下:上侧(win系统显示时间截图),下侧(cdc-query的ts_ms)
如果基本一致(不是差值8h),说明cdc-query的ts_ms是正确的的。
![[image-20230928132434484.png|325]]

3.1.5 cdc-Read数据(测试snapshot读取ts_ms字段)

![[image-20230928100333641.png]]

3.1.6 cdc-Create数据(测试incremental读取ts_ms字段)

![[image-20230928101529479.png]]

3.1.7 jdbc-RowData

![[image-20230927172538194.png]]

3.1.8 jdbc-SQL

![[image-20230927171613530.png|206]]

3.2 postgres

3.2.1 database-SQL

![[image-20230927145744323.png]]

3.2.2 cdc

cdc-RowData
![[image-20230927145825569.png]]

3.2.3 cdc-SQL(测试除ts_ms的字段)

![[image-20230927151801248.png|200]]

3.2.4 cdc-SQL-RealTime(测试ts_ms)

![[image-20230928132850256.png|325]]

3.2.5 cdc-Read数据(测试snapshot读取ts_ms字段)

![[image-20230928095911025.png]]

3.2.6 cdc-Create数据(测试incremental读取ts_ms字段)

![[image-20230928101453266.png]]

3.2.7 jdbc

jdbc-RowData
![[image-20230927173637049.png]]

3.2.8 jdbc-SQL

![[image-20230927173456643.png|212]]

3.3 sqlserver

3.3.1 database-SQL

![[image-20230927163637993.png]]

3.3.2 cdc-RowData

![[image-20230927163611807.png]]

3.3.3 cdc-SQL(测试除ts_ms的字段)

![[image-20230927163808365.png|192]]

3.3.4 cdc-SQL-RealTime(测试ts_ms)

![[image-20230928133349412.png|350]]

3.3.5 cdc-Read数据(测试snapshot读取ts_ms字段)

![[image-20230928094006306.png]]

3.3.6 cdc-Create数据(测试incremental读取ts_ms字段)

![[image-20230928101415704.png]]

3.3.7 jdbc-RowData

![[image-20230927174904854.png]]

3.3.8 jdbc-SQL

![[image-20230927182456589.png|194]]

3.4 oracle

3.4.1 database-SQL

![[image-20230927160526864.png]]

3.4.2 cdc-RowData

![[image-20230927160425443.png]]

3.4.3 cdc-SQL(测试除ts_ms的字段)

![[image-20230927160753056.png|191]]

3.4.3 cdc-SQL-RealTime(测试ts_ms)

![[image-20230928133736851.png|400]]

3.4.4 cdc-Read数据(测试snapshot读取ts_ms字段)

![[image-20230928101223538.png]]

3.4.5 cdc-Create数据(测试incremental读取ts_ms字段)

![[image-20230928101030948.png]]

3.4.7 jdbc-RowData

![[image-20230927183056565.png]]

3.4.8 jdbc-SQL

![[image-20230927182935788.png|203]]

四、结论

(1)数据库获取的without time zone在flink中都是以本地时间的存储的。可以使用LocalDateTime.ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset.UTC)直接获取。
(2)Flink中的TimestampData中存储的一般可以认为是本地时间。但需要注意:TimestampData 不可将 instant 相关方法localDateTime 、Timestamp 相关方法混用。因为instant代表与epoch时间差。而后两者代表与local是时间差。
(3)Flink程序中时间的标准值都是local本地的。因其在Sql API(sql-client)中打印出的结果会与原始数据库中打印的一致。

如下图中红色字体的是错误的数据,使用CDC需要额外注意并进行转换。
![[image-20230928164847790.png]]

五、附录

5.1 查询数据库时区SQL

-- mysql 以:time_zone 为准,system_time_zone至服务器时区
show variables like '%time_zone%';-- postgres
show time zone;-- sqlserver
DECLARE
@TimeZone NVARCHAR(255)
EXEC
master.dbo.xp_instance_regread
N'HKEY_LOCAL_MACHINE'
,
N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation'
,
N'TimeZoneKeyName'
,
@TimeZone
OUTPUT
SELECT
@TimeZone -- oracle
select dbtimezone from dual;

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

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

相关文章

【数据结构】堆的应用-----TopK问题

目录 一、前言 二、Top-k问题 &#x1f4a6;解法一&#xff1a;暴力排序 &#x1f4a6;解法二&#xff1a;建立N个数的堆 &#x1f4a6;解法三&#xff1a;建立K个数的堆&#xff08;最优解&#xff09; 三、完整代码和视图 四、共勉 一、前言 在之前的文章中&#xff…

【Kubernetes】当K8s出现问题时,我们可以从哪些方面排查出

前言 kubernetes&#xff0c;简称K8s&#xff0c;是用8代替名字中间的8个字符“ubernete”而成的缩写。是一个开源的&#xff0c;用于管理云平台中多个主机上的容器化的应用&#xff0c;Kubernetes的目标是让部署容器化的应用简单并且高效&#xff08;powerful&#xff09;,Kub…

python中dir()和help()的作用

在 Python 中&#xff0c;dir() 和 help() 是两个常用的内置函数&#xff0c;用于获取对象的属性和方法信息以及提供帮助文档。 dir(object) 函数返回一个包含对象 object 的属性和方法名称的列表。如果没有提供参数&#xff0c;则返回当前作用域内的所有名称。例如&#xff0…

DAMA-DMBOK2重点知识整理CDGA/CDGP——第14章 大数据与数据科学

目录 一、分值分布 二、重点知识梳理 1、引言 1.1 业务驱动因素 1.2 原则 1.3 基本理念 2、活动 2.1 定义大数据战略和业务需求 2.2 选择数据源 2.3 获得和接收数据源 2.4 制定数据假设和方法 2.5 集成和调整数据进行分析 2.6 使用模型探索数据 2.7 部署和监控 …

Linux CentOS7 vim多文件与多窗口操作

窗口是可视化的分割区域。Windows中窗口的概念与linux中基本相同。连接xshell就是在Windows中新建一个窗口。而vim打开一个文件默认创建一个窗口。同时&#xff0c;Vim打开一个文件也就会建立一个缓冲区&#xff0c;打开多个文件就会创建多个缓冲区。 本文讨论vim中打开多个文…

【单片机】14-I2C通信之EEPROM

1.EEPROM概念 1.EEPROM 1.1 一些概念 &#xff08;1&#xff09;一些概念&#xff1a;ROM【只读存储器---硬盘】&#xff0c;RAM【随机访问存储器--内存】&#xff0c;PROM【可编程的ROM】&#xff0c;EPROM【可擦除ROM】&#xff0c;EEPROM【电可擦除ROM】 1.2 为什么需要EE…

应用大五人格测试,来做个人职业规划

应用大五人格测试做职业规划&#xff0c;一方面能让大学生清楚知晓自己的性格特征&#xff0c;置身适合怎样的职业&#xff0c;让他们结合自己的兴趣爱好职业走向&#xff0c;进一步了解自己适合做的职业规划。另一方面可以帮助他们结合职业规划来安排人生&#xff0c;一步一个…

Transformer学习-self-attention

这里写自定义目录标题 Self-attentionMulti-head self-attention用self-attention解决其他问题 Self-attention 用Wq、Wk、Wv分别乘输入向量得到q、k、v向量 用每个q向量乘所有的k向量得到对应项的attention&#xff0c;即用每项的query向量去匹配所有的key向量&#xff0c;得…

【进阶C语言】自定义类型

本节内容大致目录如下&#xff1a; 1.结构体 2.位段 3.枚举 4.联合&#xff08;共用体&#xff09; 以上都是C语言中的自定义类型&#xff0c;可以根据我们的需要去定义。 一、结构体 一些基础知识在初阶C语言的时候已经介绍过&#xff0c;在这里粗略概括&#xff1b;重…

代码随想录算法训练营第五十五天 | 动态规划 part 12 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

目录 300.最长递增子序列思路代码 674. 最长连续递增序列思路代码 718. 最长重复子数组思路代码 300.最长递增子序列 Leetcode 思路 dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度递推公式&#xff1a;if (nums[i] > nums[j]) dp[i] max(dp[i], dp[j] 1)初…

面试总结之Spring篇

一、AOP 1、什么是AOP 1.1、概述 AOP&#xff08;Aspect-Oriented Programming&#xff09;&#xff1a;面向切面编程&#xff0c;即把一些业务逻辑中的相同代码抽取出来&#xff0c;让业务逻辑更加简练清爽 如果要CRUD写一堆业务&#xff0c;可如何实现业务代码前后进行打印…

计算机竞赛 深度学习驾驶行为状态检测系统(疲劳 抽烟 喝水 玩手机) - opencv python

文章目录 1 前言1 课题背景2 相关技术2.1 Dlib人脸识别库2.2 疲劳检测算法2.3 YOLOV5算法 3 效果展示3.1 眨眼3.2 打哈欠3.3 使用手机检测3.4 抽烟检测3.5 喝水检测 4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的驾…

WebSocket的那些事(6- RabbitMQ STOMP目的地详解)

目录 一、目的地类型二、Exchange类型目的地三、Queue类型目的地四、AMQ Queue类型目的地五、Topic类型目的地 一、目的地类型 在上节 WebSocket的那些事&#xff08;5-Spring STOMP支持之连接外部消息代理&#xff09;中我们已经简单介绍了各种目的地类型&#xff0c;如下图&…

【强化算法专题一】双指针算法

【强化算法专题一】双指针算法 1.双指针算法--移动零2.双指针算法--复写零3.双指针算法--快乐数4.双指针算法--盛水最多的容器5.双指针算法--有效三角形的个数6.双指针算法--和为s的两个数7.双指针算法--三数之和8.双指针算法--四数之和 1.双指针算法–移动零 算法原理解析----…

【JavaScript】读取本地json文件并绘制表格

本文为避免跨域问题&#xff0c;使用了改造过的本地json文件的方法实现读取json数据并绘制表格。 如果发起http请求获取本地 json文件中数据&#xff0c;需要架设本地服务器&#xff0c;本文不做阐述。 概述 1、json在本地&#xff0c;并不需要从服务器下载。 2、采用jquery…

国庆作业day5

应用层&#xff1a;提供用户与网络应用程序之间的接口。表示层&#xff1a;负责数据的格式转换、加密和解密。会话层&#xff1a;负责建立、管理和终止会话。它提供会话控制和同步&#xff0c;允许应用程序之间建立连接和交换数据。传输层&#xff1a;提供端到端的连接。网络层…

postgresql-管理数据表

postgresql-管理数据表 创建表数据类型字段约束表级约束模式搜索路径 修改表添加字段删除字段添加约束删除约束修改字段默认值修改字段数据类型重命名字段重命名表 删除表 创建表 在 PostgreSQL 中&#xff0c;使用 CREATE TABLE 语句创建一个新表&#xff1a; CREATE TABLE …

专业PDF编辑阅读工具PDF Expert mac中文特点介绍

PDF Expert mac是一款专业的PDF编辑和阅读工具。它可以帮助用户在Mac、iPad和iPhone等设备上查看、注释、编辑、填写和签署PDF文档。 PDF Expert mac软件特点 PDF编辑&#xff1a;PDF Expert提供了丰富的PDF编辑功能&#xff0c;包括添加、删除、移动、旋转、缩放、裁剪等操作…

树莓派4B与STM32串口通信

目录 2上篇文章的补充 2.1 树莓派通信设置 3树莓派与STM32通信 3.1接线准备 3.2代码 3.2.1 STM32代码&#xff1a; 3.2.2树莓派代码&#xff1a; 2上篇文章的补充 2.1 树莓派通信设置 在上篇文章的基础上&#xff0c;进一步的设置 终端输入&#xff1a;sudo minicom …

从 0 到 1 ,手把手教你编写《消息队列》项目(Java实现) —— 核心类持久化存储

文章目录 一、持久化存储的方式与路径二、公共模块序列化 / 反序列化异常规定 三、持久化存储数据库数据管理文件数据管理读写规定新增 /删除规定内存中 Message 的规定存储规定代码编写 硬盘数据管理 一、持久化存储的方式与路径 交换机,队列,绑定关系,这些我们使用数据库来管…