关于debezium同步mysql字段类型datetime、date、time、tim... 20251444编辑
Heaven helps those who help themselves
资深码农+深耕理财=财富自由
欢迎关注
资深码农+深耕理财=财富自由
欢迎关注

关于debezium同步mysql字段类型datetime、date、time、timestamp的格式转换说明
Created by Marydon on 2023-12-22 16:29
1.情景展示
使用debezium的插件:debezium-connector-mysql(io.debezium.connector.mysql.MySqlConnector),自动读取mysql日志binlog相关表的数据变更记录,然后将其发布到kafka topic当中。
现在遇到的问题是:
在mysql当中,表示日期类型的数据类型有:datetime、date和timestamp;
表示时间类型的是:time。
当使用io.debezium.connector.mysql.MySqlConnector插件读取mysql数据后,debezium自动对日期类型进行了格式转换。
2.具体分析
先说都转成了什么数据类型,再说怎么解决。
如上图所示,该表当中每个日期类型都有,下面我们进行实战演练。
抓取数据
我使用的REST API的方式来抓取mysql数据。
消费数据
得到其中一条数据如下:
所使用的debezium-connector-mysql插件版本号:2.2.1
id=4的mysql数据展示如下:
由此可以得出以下结论:
mysql datetime类型:使用的转换类是io.debezium.time.Timestamp,最终转成了时间戳(1970年01月01日0时0分0秒到指定日期的毫秒数),形如:1702027934000。
mysql date类型:使用的转换类是io.debezium.time.Date,最终转成了天数(1970年01月01日到指定日期的天数),形如:19699。
mysql timestamp类型:使用的转换类是io.debezium.time.ZonedTimestamp,最终转成了UTC时间,形如:2023-12-08T15:32:19Z
mysql time类型:使用的转换类是io.debezium.time.MicroTime,最终转成了微妙数(将小时转成了微妙),形如:34341000000。
3.解决方案
在mysql当中,最常用的是datetime类型,当将我们将时间戳转回日期字符串时,发现:所得时间比原来的时间早了8个小时。
这是因为:debezium在将datetime类型转成时间戳时,所用时区为:UTC,而我们在解析时间的时候,用的时区却是:UTC+8,所以最终转换得来的时间会比实际时间早8个小时。
网上搜到的解决办法都是:
无论是设置连接数据库所用时区还是设置数据库服务时间为东八区,统统不管用!
debezium在进行日期格式转换时,使用的是UTC,这是在代码里面写死的,所以你再怎么设置数据库时间都无济于事!
推荐使用第三种解决方案
第一种方案:更改debezium源码
源码地址:https://github.com/debezium/debezium
更改源码后,重新打包。
第二种方案:自定义开发Sink Connector
既然我们没有办法通过参数设置,将日期还原成正确时区,那我们完全可以从kafka拿数据,然后自行解析。
先说如何将日期还原成真实日期。
datetime还原
// 年月日(大写M:表示月份,小写m:表示分钟) public static final String FORMAT_DATE = "yyyy-MM-dd"; // 时分秒(大写H:表示24小时制,小写h:表示12小时制) public static final String FORMAT_TIME = "HH:mm:ss"; // 年月日时分秒 public static final String FORMAT_DATE_TIME = FORMAT_DATE + " " + FORMAT_TIME; public static String timestampToString(Long timestamp, String timeZone) { if (String.valueOf(timestamp).length() == 16) {// 16:毫秒 return toDateTimeString(fromTimeMills(timestamp / 1000, timeZone), FORMAT_DATE_TIME); } else {// 13:秒 return toDateTimeString(fromTimeMills(timestamp, timeZone), FORMAT_DATE_TIME); } } public static LocalDateTime fromTimeMills(long timeMills, String timeZone){ return LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMills), ZoneId.of(timeZone)); } /** * 日期转字符串(日期+时间) * @attention: jdk>=1.8 * @date: 2020年08月31日 0031 17:04 * @param: dateTime * @param: pattern * @return: java.lang.String */ public static String toDateTimeString(LocalDateTime dateTime, String pattern) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); return dateTimeFormatter.format(dateTime); }
调用
timestampToString(1702027934000L,"UTC");// 2023-12-08 09:32:14
date还原
/** * 根据天数倒推日期 * https://www.cnblogs.com/Marydon20170307/p/10672030.html * @param days * @return */ public static String getSomeDay(int days){ SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE); Date date; try { date = sdf.parse("1970-01-01"); } catch (ParseException e) { throw new RuntimeException(e); } Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_YEAR, days); date = calendar.getTime(); return sdf.format(date); }
调用
getSomeDay(19699);// 2023-12-08
timestamp还原
/** * ISO 8601标准日期转成字符串 * @param dateTimeStr * 2023-12-07T16:00:00Z * "2023-12-07T16:00:00Z"是一种ISO 8601标准的日期时间表示方式 * 这个字符串表示的是一个特定的时间点:2023年12月7日,下午4点(16点),0分钟,0秒。其中“T”是时间标识符,“Z”表示的是协调世界时(UTC)。 * 这种格式是可以精确到秒的时间戳 * @return */ public static String fromISO8601(String dateTimeStr) { return toDateTimeString(toLocalDateTime(dateTimeStr), FORMAT_DATE_TIME); } /** * 日期字符串按指定格式转LocalDateTime * @attention: * @date: 2021/7/28 15:05 * @param: dateTimeStr 日期字符串 * 2023-12-07T16:00:00Z * "2023-12-07T16:00:00Z"是一种ISO 8601标准的日期时间表示方式 * 这个字符串表示的是一个特定的时间点:2023年12月7日,下午4点(16点),0分钟,0秒。其中“T”是时间标识符,“Z”表示的是协调世界时(UTC)。 * 这种格式是可以精确到秒的时间戳 * @return: java.time.LocalDateTime */ public static LocalDateTime toLocalDateTime(String dateTimeStr) { // UTC时间 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeStr, formatter); // TODO return zonedDateTime.toLocalDateTime().plusHours(-6); }
说明:将UTC时间转成本地时间后,需要向前或向后推几个小时,需要自己算一下。
这里的-6,不一定对,我也不知道debezium是怎么进行转换的,竟然比实际时间早了6个小时,而不是8个小时。
调用
fromISO8601("2023-12-08T15:32:19Z");// 2023-12-08 09:32:19
至于自定义开发Sink Connector组件,请看文末推荐。
2024年2月19日16:54:19
第三种方案:使用io.debezium.connector.jdbc.JdbcSinkConnector完成数据同步(推荐使用)
由于网络上的误导,上面两种方式都走偏了。
其实,使用debezium官方组件debezium-connector-jdbc来同步debezium-connector-mysql组件生成的数据,数据是可以实现正常转换的。
无需我们再进行手动转换!!!
2024-06-17 10:56:39
当源库是mysql,源表有timestamp字段,且使用debezium-connector-mysql捕获数据,且目标表要同步源表的timestamp类型字段时,timestamp字段在同步至目标表时,会存在时间差的问题,解决方案需要分情况讨论:
如果目标库是mysql,用debezium-connector-jdbc订阅数据,debezium-connector-mysql需要增加配置参数:database.connectionTimeZone=GMT+8;
如果目标库是oceanbase,用debezium-connector-jdbc订阅数据,debezium-connector-mysql需要增加配置参数:database.connectionTimeZone=GMT+8;
如果目标库是sqlserver,用debezium-connector-jdbc订阅数据,debezium-connector-mysql需要增加配置参数:database.connectionTimeZone=GMT;
如果目标库是oracle,用debezium-connector-jdbc订阅数据,debezium-connector-mysql需要增加配置参数:database.connectionTimeZone=GMT。
4.拓展
mysql(debezium-connector-mysql)
datetime类型:会被转成io.debezium.time.Timestamp;
date类型:会被转成io.debezium.time.Date;
timestamp类型:会被转成io.debezium.time.ZonedTimestamp;
time类型:会被转成io.debezium.time.MicroTime。
oracle(debezium-connector-oracle)
date类型(包含带时间和不带时间):会被转成io.debezium.time.Timestamp;
timestamp类型:会被转成io.debezium.time.MicroTimestamp。
sqlserver(debezium-connector-sqlserver)
datetime类型:会被转成io.debezium.time.Timestamp;
datetime2类型:会被转成io.debezium.time.Timestamp;
date类型:会被转成io.debezium.time.Date;
smalldatetime类型:会被转成io.debezium.time.Timestamp;
datetimeoffset类型:会被转成io.debezium.time.ZonedTimestamp;
time类型:会被转成io.debezium.time.MicroTime。
说明:
至于将debezium转换后date类型数据,如何转回来,感兴趣的,可以看文末推荐的假删除文章。
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!
相关推荐:
与君共勉:最实用的自律是攒钱,最养眼的自律是健身,最健康的自律是早睡,最改变气质的自律是看书,最好的自律是经济独立 。
您的一个点赞,一句留言,一次打赏,就是博主创作的动力源泉!
↓↓↓↓↓↓写的不错,对你有帮助?赏博主一口饭吧↓↓↓↓↓↓
本文来自博客园,作者:Marydon,转载请注明原文链接:https://www.cnblogs.com/Marydon20170307/p/17921900.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具