1 背景

由于数据同步和数据汇聚中,常常需要从多个数据源中获取数据,这些数据源可能来自不同的厂商、不同的部门、甚至不同的国家或地区。这些数据源之间的数据格式、数据结构、甚至数据语言都可能存在差异,因此需要将它们进行结构转换,以便能够在一个平台上对这些数据进行管理、分析和使用。

2 技术实现

2.1 自写工具类实现

1 公用类

import lombok.Data;@Data
public class DdlChangeInfo {/*** 表名*/private String tableName;/*** 来源数据库DDL*/private String sourceDdl;/*** 目标数据库DDL*/private String targetDdl;/*** 来源数据库类型*/private String sourceSqlType;/*** 目标数据库类型*/private String targetSqlType;
}
import java.util.List;public interface IDdlChangeStartegy {void change(List<DdlChangeInfo> ddlChangeInfoList);
}

2 转换类

MySQL->PostgreSQL

import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** Mysql转Postgresql DDL策略*/
@Slf4j
public class Mysql2PosgresqlDdlChangeStartgy implements IDdlChangeStartegy {@Overridepublic void change(List<DdlChangeInfo> ddlChangeInfoList) {for (DdlChangeInfo ddlChangeInfo : ddlChangeInfoList) {String ddl = ddlChangeInfo.getSourceDdl().replaceAll("current_timestamp\\(\\) ON UPDATE current_timestamp\\(\\)", "current_timestamp").replaceAll("current_timestamp\\(\\)", "current_timestamp").replaceAll("current_timestamp\\(\\)", "current_timestamp").replaceAll("int\\([0-9]*\\)", "INT").replaceAll("tinyint\\([0-9]*\\)", "INT").replaceAll(" tinyINT ", "INT").replaceAll("double\\([0-9]*,[0-9]*\\)", "float8").replaceAll(" double ", " float8 ").replaceAll(" datetime ", " timestamp(6) ").replaceAll("DEFAULT 00000000000", "DEFAULT 0").replaceAll("unsigned zerofill", "").replaceAll("bigint\\([0-9]*\\) NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY").replaceAll("bigint\\([0-9]*\\)", "INT8");try {Statements statements = CCJSqlParserUtil.parseStatements(ddl);statements.getStatements().stream().map(statement -> (CreateTable) statement).forEach(ct -> {Table table = ct.getTable();List<ColumnDefinition> columnDefinitions = ct.getColumnDefinitions();List<String> comments = new ArrayList<>();List<ColumnDefinition> collect = columnDefinitions.stream().peek(columnDefinition -> {List<String> columnSpecStrings = columnDefinition.getColumnSpecStrings();int commentIndex = getCommentIndex(columnSpecStrings);if (commentIndex != -1) {int commentStringIndex = commentIndex + 1;String commentString = columnSpecStrings.get(commentStringIndex);String commentSql = genCommentSql(table.toString(), columnDefinition.getColumnName(), commentString);comments.add(commentSql);columnSpecStrings.remove(commentStringIndex);columnSpecStrings.remove(commentIndex);}columnDefinition.setColumnSpecStrings(columnSpecStrings);}).collect(Collectors.toList());ct.setColumnDefinitions(collect);String createSQL = ct.toString().replaceAll("`", "\"").replaceAll("BIGINT UNIQUE NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY").replaceAll("BIGINT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY").replaceAll("BIGINT NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY").replaceAll("INT NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY").replaceAll("INT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY").replaceAll("IF NOT EXISTS", "").replaceAll("TINYINT", "SMALLINT").replaceAll("DATETIME", "TIMESTAMP").replaceAll(", PRIMARY KEY \\(\"id\"\\)", "");// 如果存在表注释if (createSQL.contains("COMMENT")) {createSQL = createSQL.substring(0, createSQL.indexOf("COMMENT"));}StringBuilder postgresqlDdl = new StringBuilder();postgresqlDdl.append(createSQL + ";");comments.forEach(t -> postgresqlDdl.append(t.replaceAll("`", "\"") + ";"));ddlChangeInfo.setTargetDdl(postgresqlDdl.toString());});} catch (Exception e) {log.error(e.getMessage(), e);}}}/*** 获得注释的下标** @param columnSpecStrings columnSpecStrings* @return 下标*/private static int getCommentIndex(List<String> columnSpecStrings) {for (int i = 0; i < columnSpecStrings.size(); i++) {if ("COMMENT".equalsIgnoreCase(columnSpecStrings.get(i))) {return i;}}return -1;}/*** 生成COMMENT语句** @param table        表名* @param column       字段名* @param commentValue 描述文字* @return COMMENT语句*/private static String genCommentSql(String table, String column, String commentValue) {return String.format("COMMENT ON COLUMN %s.%s IS %s", table, column, commentValue);}
}

其他类型的转换待补充

3 测试类

MySQL->PostgreSQL

import net.sf.jsqlparser.JSQLParserException;import java.util.ArrayList;
import java.util.List;public class MysqlDdl2PgDdlTestMain {public static void main(String[] args) throws JSQLParserException {List<DdlChangeInfo> ddlChangeInfoList = new ArrayList<>();DdlChangeInfo ddlChangeInfo0 = new DdlChangeInfo();ddlChangeInfo0.setSourceDdl("CREATE TABLE `t_order` (" +"  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键'," +"  `goods_id` int(11) DEFAULT NULL COMMENT '商品id'," +"  `goods_name` varchar(255) DEFAULT NULL COMMENT '商品名称'," +"  `dealer_id` int(11) DEFAULT NULL COMMENT '经销商id'," +"  `dealer_name` varchar(255) DEFAULT NULL COMMENT '经销商名称'," +"  `goods_num` int(11) DEFAULT NULL COMMENT '商品数量'," +"  `amount` decimal(10,2) DEFAULT NULL COMMENT '折前金额'," +"  `discount_amount` decimal(10,2) DEFAULT NULL COMMENT '折后金额'," +"  `discount` double DEFAULT NULL COMMENT '折扣'," +"  `order_time` datetime DEFAULT NULL COMMENT '订单时间'," +"  `status` int(11) DEFAULT NULL COMMENT '订单状态,0:未支付 1:已支付'," +"  `create_time` datetime DEFAULT NULL COMMENT '创建时间'," +"  `update_time` datetime DEFAULT NULL COMMENT '更新时间'," +"  PRIMARY KEY (`id`)" +");");ddlChangeInfo0.setTableName("t_order");ddlChangeInfoList.add(ddlChangeInfo0);DdlChangeInfo ddlChangeInfo1 = new DdlChangeInfo();ddlChangeInfo1.setSourceDdl("CREATE TABLE `t_order_1` (" +"  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键'," +"  `goods_id` int(11) DEFAULT NULL COMMENT '商品id'," +"  `goods_name` varchar(255) DEFAULT NULL COMMENT '商品名称'," +"  `discount` double DEFAULT NULL COMMENT '折扣'," +"  `order_time` datetime DEFAULT NULL COMMENT '订单时间'," +"  `status` int(11) DEFAULT NULL COMMENT '订单状态,0:未支付 1:已支付'," +"  `create_time` datetime DEFAULT NULL COMMENT '创建时间'," +"  `update_time` datetime DEFAULT NULL COMMENT '更新时间'," +"  PRIMARY KEY (`id`)" +");");ddlChangeInfo1.setTableName("t_order_1");ddlChangeInfoList.add(ddlChangeInfo1);System.out.println("init:" + ddlChangeInfoList);Mysql2PosgresqlDdlChangeStartgy mysql2PosgresqlDdlChangeStartgy = new Mysql2PosgresqlDdlChangeStartgy();mysql2PosgresqlDdlChangeStartgy.change(ddlChangeInfoList);System.out.println("changed:" + ddlChangeInfoList);}
}

其他类型待待补充

2.2 基于dbswitch实现

1 介绍

dbswitch是一款数据库迁移工具,它可以帮助用户轻松地将一个数据库系统中的数据迁移到另一个数据库系统中。它支持多种常见的关系型数据库系统,例如MySQL、Oracle、SQL Server、PostgreSQL等。dbswitch提供了丰富的转换选项和功能,可以帮助用户解决在不同数据库系统之间存在的格式差异、数据类型转换、编码转换等问题,确保迁移后的数据准确、完整、一致性。dbswitch的优势在于它的灵活性和可定制性。用户可以根据自己的需求和环境,选择不同的转换方式和配置选项,以便更好地控制迁移过程和结果。

2 实践

待补充

参考文档:

DBSwitch阉割版实现异构数据库表结构同步_程序员小王java的博客-CSDN博客

3 问题分析和总结

异构数据源DDL转换的两种方式相关推荐

  1. unicode和字符串之间的转换有两种方式

    unicode和字符串之间的转换有两种方式. 1.1.通过JDK自带的"native2ascii"进行转换     首先,您测试的机器需要安装JDK,比如我的机器环境,我的JDK安 ...

  2. matlab 转换 tfrecord,训练数据集与TFRecord互相转换的两种方式

    TensorFlow使用TFRecord格式来统一存储数据,该格式可以将图像数据.标签信息.图像路径以及宽高等不同类型的信息放在一起进行统一存储,从而方便有效的管理不同的属性. 将训练数据集转成TFR ...

  3. ABAP和XML数据格式互相转换的两种方式

    ABAP和XML数据格式互相转换是广大开发人员经常遇到的需求.本文介绍两种方式. 1. ABAP提供了一个工具类cl_proxy_xml_transform,通过它的两个方法abap_to_xml_x ...

  4. java中byte数组与int类型的转换(两种方式)

    java中byte数组与int类型的转换,在网络编程中这个算法是最基本的算法,我们都知道,在socket传输中,发送.者接收的数据都是 byte数组,但是int类型是4个byte组成的,如何把一个整形 ...

  5. 任意进制转换java_Java 任意进制转换(两种方式)

    本文提供两种Java实现任意进制转换的方法: 方法一:利用 Integer 实现进制转换 1. Integer类的方法toBinaryString(),Integer.toOctalString(), ...

  6. SpringBoot实现多数据源的两种方式

    前言 公司项目有连接多个不同数据库的需求,特研究了一下,根据网上的资料,造了一个基于AOP方式的数据源切换轮子,但继续探索,突然发现有开源的多数据源管理启动器.不过,本篇两种方式都会介绍. 基于dyn ...

  7. Dagger2 知识梳理(1) Dagger2 依赖注入的两种方式

    一.资料推荐 最近这几天一直在看有关Dagger2有关的文章,感觉就是这东西真难用.真难懂,数次想要放弃,还好有网上大神的教程帮助,模模糊糊总算能把基本的几个概念跑通了. 这里首先推荐 牛晓伟 的下面 ...

  8. WebService的两种方式SOAP和REST比较 (转)

    由于第一次接触WebService,对于很多概念不太理解,尤其是看到各个OpenAPI的不同提供方式时,更加疑惑.如google map api采用了AJAX方式,通过javascript提供API, ...

  9. Python字符串的两种方式——百分号方式,format的方式

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

最新文章

  1. linux网络命名空间详解,Linux Network Namespace (netns) 详解
  2. c++ 读取访问权限冲突_关于Windows文件6项基础权限的一些设置!
  3. python中的装饰器怎么运行_Python 装饰器入门(上)
  4. php中update()函数,update_option()函数
  5. python打开伪终端_0xB:伪终端
  6. 我最看不惯的几个公众号
  7. 打印工资条怎么做到每个人都有表头明细_使用工资条生成器,“智”作工资条...
  8. Powerdesigner概念模型并将概念模型转换成物理模型
  9. win7计算机打开显卡设置在哪,[win7显卡设置在哪里]WIN7显卡优化设置在哪
  10. outlook2010保留服务器邮件,outlook 保留服务器邮件
  11. Word2vec And Doc2vec - 文本向量化
  12. 在windows下使用docker做本机linux环境系统测试
  13. python中那些双下划线开头的那些函数都是干啥用用的
  14. 百度网盘的探险:云存储如何逃离“德鲁克”困境
  15. 宏昆酒店集团携手DataPipeline打造实时数据融合平台,酒店业精益管理的新秘诀
  16. 探索React生态圈
  17. 电子商务专业(技术方向)学习经验(忠告)
  18. Linux系统设置root用户密码
  19. 码云新增 PR 显示权限助力计算机教学
  20. 木马编程DIY (Delphi版) - 第3篇 星号密码查看工具

热门文章

  1. 第二届“长安杯”电子数据竞赛试题wp
  2. c语言中缺少参数怎么弄,printf参数不足
  3. 关于打包处理less文件时遇见的问题:
  4. 计算机系统结构知识总结,计算机基础知识总结
  5. DAU/MAU?UGC?
  6. Postgresql日期转字符串
  7. Python math库函数
  8. 钉钉直播教学中遇到的26个常见问题解决方法
  9. 屏幕录像制作gif动态图
  10. SQL Server 2012介绍