我与数据库的十年 | 从MySQL到TencentDB,带你实现数据治理平台

2024-08-14 17:44:25 浏览数 (3)

前言

在观看腾讯云开发者社区打造的纪录片《中国数据库前世今生》时,了解了中国数据库从无到有、破茧化蝶的发展历程。在充满感动和感慨之余,让我不仅想起了在这十年里,被数据库影响的程序员人生。

2014年我还在大二,在期末考试的前夕,为了数据库不挂科,我熬夜在笔记本上搭建了第一个MySQL用来练习,后来在大学的课程上又学习了sqlserver、oracle。时间匆匆,六月的毕业季来的总是猝不及防。在毕业的那年,赶上了“去IOE”的浪潮,这标志着oracle的落幕,从此国产化数据库进入了一个全新的时代。

曾几何时,我对于数据库的使用和理解就是“用来存储数据的地方”。尤其在日常传统开发中,数据库都是用来存储用户信息以及各种后台数据的,在后端服务中连接数据库,前端通过API请求数据渲染在浏览器上,以此完成整个业务流程。

后来在投身大数据行业,列式数据库、OLAP、数据仓库、内存数据库等数据库冲击着我的专业领域,海量的数据不再存储于MySQL这种关系型数据库,也不再只服务于单一的业务场景,海量的数据摇身一变变成了“数据资产”,于是我也在数据库这条路上,开启了数据治理新篇章。

关于数据治理

什么是数据治理?为什么要数据治理?如何数据治理?这是我们需要考虑的三个问题。

我理解的数据治理

以前我们只是在数据库中存储数据,业务少、开发人员少、数据表少。但随着业务上涨、开发人员增多、数据表的增加以及各种数据库和数据仓库的出现,首先是对最基本的表名进行了规范,例如接入的源数据要以ODS开头,经过ELT处理汇总之后的表就是DW开头,ds结尾的是日表、dm结尾的是月表等。

接着就是对表结构的管理,我们在接入数据的时候,通常会根据数据规范来建表,然后再加数据load到表中。但是对于其他开发者来说,我想知道这个表字段的含义,我该问谁要规范呢?所以为了解决这个问题,引出了元数据管理

每次接入一种数据、接入一个表,负责人都将表名、表字段录入一个系统中,其他人使用时只要在这个系统中查询,就对这个表信息一目了然。

这样所有的表结构都对所有开发者进行了开放,开发者就可以随心所欲的去数据库中查询所有的数据,但是往往有些信息是敏感的,而且对于一个多租户的大数据平台来说,数据隔离和权限控制更是很必要的。所以针对于这种需求,我们需要一个系统来实现“数据金库”。

数据金库将数据的查询入口限制在系统之中,不允许用户(租户)使用后台命令行去绕行查询,每次查询都会有管理者审批,每个用户只能查询有权限的数据库和表数据,而敏感信息也会进行脱敏,这就是数据治理中的数据安全

我在上面说到的系统,指的就是数据治理模块,这里为什么叫做模块,而且不是平台。因为上升到平台层面,这个平台除了数据治理外,还会涉及数据模型、数据开发、数据调度、数据交换以及团队管理等等各个模块。

简单来说,数据治理就是对不同数据库中的数据,按照需求进行管理,而数据治理平台就是将数据治理的结果,开放给租户/团队。

数据治理内容

借鉴资产管理的方法理论来管理数据,将数据作为一种特殊的资产,对数据进行标准化的规范约束,并以元数据作为驱动,连接数据的标准管理、数据质量管理、数据数据安全管理的各个阶段,形成统一、完善的数据治理体系,以解决实际业务问题为导向,增强数据对业务发展的支撑能力。

数据治理内容具体包括:

  1. 数据标准管理:建设一套数据标准体系,为建设数据资产化提供保障,提供一套数据标准管理支撑工具,对参与的人、数据进行标准化统一管理。
  2. 元数据管理:集中管理O域数据、流式数据元数据,提供元数据集中创建、维护、查询等功能。
  3. 数据质量管理:向数据质量用户提供平台化的数据质量监控与评估,包含扩充和优化公共规则库、增加评估知识库、提升不同类型数据源和数据仓库的兼容性等;降低用户使用门槛,提升用户易用性和用户体验。
  4. 数据资产管理:以资产的角度开展数据管理工作,有助于多角度、全方位开展数据的管理,达成数据到数据资产的目标。
  5. 数据安全管理:实现用户安全和数据安全管理,对平台使用者进行权限控制和审计,对数据进行脱敏和加密。

而数据治理平台的实现,就是将理论应用在实践中。而提到平台,又回到了最原始的前后端业务,我们需要一个MySQL数据库,来存储数据治理平台的后台数据。

TencentDB for MySQL

在数据治理中,数据库的HA高可用是重中之重。因为数据治理平台所有的数据(数据的元数据、租户信息数据、任务调度数据等)都存储MySQL中。随着任务增加、峰值集中调度或者一些租户的使用不当,一旦数据库QPS到达瓶颈或者宕机,就会导致严重的安全事故。

数据库架构

当前在数据治理平台的架构中,我们使用浮动IP映射了两个MySQL数据库,一个主库一个备库,主备之间会进行数据同步。当主库出现访问故障时,备库才会接管平台的数据操作。

在整个数据治理平台的架构中,很多模块都会频繁的对数据库进行操作。例如任务调度模块,为了满足调度任务的实时性,所以要频繁扫描MySQL中的调度任务表。同时大量的调度日志、监控日志也会写入到MySQL中。

所以选择一个易扩展(应对业务量上涨)、高可用且满足高QPS的数据库产品,是构建数据治理平台的基础,也是重中之重。而纵观各个云数据库产品,腾讯云的TencentDB for MySQL,最贴合数据治理对于数据库的要求。

腾讯云数据库TencentDB for MySQL是腾讯云基于开源数据库MySQL专业打造的高性能企业级数据库服务,完全兼容 MySQL 协议,所以使用MySQL的业务场景都可以都可以使用云数据库。

优势

对比了很多云数据库产品,TencentDB for MySQL除了具有价格便宜之外,我选择它来完成数据治理,更多的是因为产品本身的优势:

  1. 高可用性:实时热备实时双机热备,自动容灾提供宕机自动检测和故障自动迁移,数据库代理供数据库代理服务,代理应用服务访问数据库时的所有请求,降低主库负载。
  2. 高安全性:可以集成腾讯云的DDoS防护、数据库攻击防护以及数据库审计提供金融级数据审计功等,能帮助用户抵御各种攻击,保证业务的正常运行和数据安全性。
  3. 高可靠性:闪回查询提供闪回查询能力,节省大量的数据查询和恢复时间,使误操作后的数据能够快速恢复,从而保障业务快速恢复运行。极速回档、异地备份容灾。
  4. 高稳定性:自动弹性扩缩容、就近访问、低网络延时。

我们从TencentDB的全场景高可用性架构可以看出,TencentDB关于用户访问MySQL实例和数据备份的实现。

购买TencentDB

进入腾讯云数据库TencentDB for MySQL页面,选择数据库的版本、架构和实例配置。

然后设置网络。

这里的网络和安全组使用默认的配置即可,接着就是设置字符集、数据库密码以及数据复制方式。

最后确认配置信息。

开启公网ip

购买成功之后,在控制台就可以看到MySQL实例。

点击管理按钮,进入TencentDB管理页面,开启公网IP。

开启之后,公网IP和端口就会显示,内网默认端口是3306,外网端口是随机分配。

如果想要保证访问安全性,也可以关闭外网地址。

登录TencentDB

根据上面TencentDB实例的公网IP,然后使用root用户以及之前我们设置的密码,就可以通过终端的命令行进行登录。

平台技术架构

之前基于前端Vue Element Plus实现的后台管理系统BuildAdmin,我一边拆解一边实现了管理系统中每个模块,最后写了BuildAdmin后台管理系统实现专栏。

最后的后台管理系统效果如下:

今天我们就是基于这个后台管理系统,来实现一个数据治理平台,所以整个数据治理平台的前端选型就是vue3 ElementPlus TypeScript Sass Pinia Vue-router,至于后端实现就是java的Sprintboot。

实现思路

因为数据治理平台包含的模块很多,从用户层的租户/团队模块,到平台层的数据资产、任务开发、模型管理等模块,以及到连接底层的数据源管理和授权模块,仅靠一个人短时间内无法开发完成。

所以我们本篇文章选择元数据管理模块的元数据展业页面,完成与TencentDB的数据联动。整个后台管理系统的架构都已经具备,我只需要开发元数据管理相关的页面,然后挂载到router即可。

数据架构

元数据管理是对众多数据库中的数据表进行一个描述,其中包括字段名称、字段中文名称、字段类型、字段描述等。这些描述数据(元数据)存放在TencentDB MySQL中,然后前端通过调用后端接口去查询这些数据渲染在页面上。

在数据治理中,数据表的数据源很多,例如MySQL、MPP数据库、Hive数据仓库以及各种关系型数据。通常元数据模块又分为采集模块和管理模块。

在管理模块中我们可以通过页面录入元数据信息,在采集模块中我们可以通过采集任务,采集元数据补充到元数据表中,然后数据资产管理模块,就可以查到这些元数据信息。

管理系统准备工作

首先是修改logo和菜单,我在网上找了一个图标,然后修改管理系统的名称。

代码语言:html复制
<template>
    <div class="layout-logo">
        <img v-if="!config.layout.menuCollapse" class="logo-img" src="/@/assets/logo1.png" alt="logo"/>
        <div v-if="!config.layout.menuCollapse"
             class="website-name">
            数据治理平台
        </div>
        <Icon
            v-if="config.layout.layoutMode != 'Streamline'"
            @click="onMenuCollapse"
            :name="config.layout.menuCollapse ? 'fa fa-indent' : 'fa fa-dedent'"
            :class="config.layout.menuCollapse ? 'unfold' : ''"
            size="18"
            class="fold"
        />
    </div>
</template>

菜单栏的请求其实是基于后台返回的json进行渲染的,但是我在之前[

BuildAdmin05:如何玩转Vue路由动态加载

](https://cloud.tencent.com/developer/article/2381454)提到了,因为当时还没有实现后台,所以就将后端返回的菜单json写死在了router.ts这个工具类中,所以我们直接去添加或者修改菜单即可,这里先添加两个目录(后续会根据需求修改)。

初版的数据治理平台样式如下:

上面这些都是对aside、header区域很简单的一些修改,而实现数据治理平台更多的工作设计main区域的功能页面。所以我就根据我的一些经验,设计了一个元数据管理展示页面。

前台设计

前台的设计就是针对于layout布局中的main区域,完成元数据管理模块的设计。

元数据展示页面

从main区域自上向下、自左向右开始设计。

1. title

首先是元数据展示页面的title的设计。找了一个图标、然后是数据表的中文名、英文名、描述以及两个标签。

代码语言:html复制
<div class="top-title">
    <div class="table-logo">
        <Icon name="local-datainfo" size="40" color="#3f0a553"></Icon>
    </div>
    <div class="table-info">
        <p>中文表名</p>
        <p>英文表名</p>
        <p class="table-describe">描述:xxx</p>
    </div>

    <div class="table-tags">
        <el-tag type="primary">A</el-tag>
        <el-tag type="success">B</el-tag>
    </div>
</div>

基本的样式如下:

2. flex布局

然后css样式设计,根据我自己预期的样进行flex弹性布局,就是各种div嵌套、flex样式布局。

代码语言:css复制
.top-title {
    display: flex;
    align-items: center;
}

.table-info {
    width: 30%;
    display: flex;
    flex-direction: column;
    margin-left: 27px;
    text-align: left;

    & .table-describe {
        opacity: 0.5;
    }
}

.table-logo {
    margin-left: 57px;
}

.table-tags {
    margin-left: 87px;

    & .el-tag {
        margin-left: 17px;
    }
}

最后样式如下:

元数据展示Table

在timeline的右侧区域就是元数据的展示区域,这里使用ELement Plus的el-table实现的。其实这一块的设计整体来说比较中规中矩,只不过在设置table的各种样式的时候,会遇到一些细节问题需要自己解决。

目前表格都是复制的Element Plus关于table的代码。这里主要是对el-table的两种应用:一种是没有表头的,奇数列为表头,偶数列为实际值;另一种是有由表头的。有无表头由show-header属性控制。

基本信息

首先第一个table是基本信息,我们拷贝下面的官网代码:

因为这里我想奇数列为表头,偶数列为实际值,而且奇数列要添加背景色,所以根据需求进行改造。

首先先定义我们需要渲染的数据格式:

然后将数据绑定到el-table上。

代码语言:html复制
<div class="metadata-table">
    <el-table :data="baseInfo" border style="width: 100%;"
              :show-header="false">
        <el-table-column prop="first_title" width="150"/>
        <el-table-column prop="first_value" align="center"/>
        <el-table-column prop="second_title" width="150"/>
        <el-table-column prop="second_value" align="center"/>
    </el-table>
</div>

show-header设置为false来去掉表头,这样将数据按照我们的要求渲染成功了.

但是我想要奇数列添加背景色,需要添加额外的选择器样式:

代码语言:css复制
& :deep(.el-table__row > :nth-child(2n 1)) {
    background-color: #eef1f6;
}

同时我还想自定义边框的样式,单纯的使用border是没有任何效果的,需要设置下面的css样式:

代码语言:css复制
:deep(.el-table) {
    border-bottom: 1px solid #000;
    border-right: 1px solid #000;
    margin: 0 auto;
}

:deep(.el-table__row) {
    border-bottom: 1px solid #000;
    border-right: 1px solid #000;
    margin: 0 auto;
}

:deep(.el-table th) {
    border: 1px solid #000;
    border-right: none;
    border-bottom: none;
}

:deep(.el-table td) {
    border: 1px solid #000;
    border-right: none;
    border-bottom: none;
}

/**改变表头标题颜色*/
:deep(.el-table thead) {
    color: #000;
}

:deep(.el-table) {
    border: 1px solid #000;
}

最后实现了我们想要的样式(颜色后期再调):

字段结构

接下来就是元数据管理中最重要的字段结构,我们做元数据管理更多的是想要知道表字段的含义。在这个table的设计上就是常见的表头 表数据的样式。同样我们先定义数据:

然后根据数据定义table:

代码语言:html复制
<div class="metadata-table">
    <el-table :data="fields_info" border style="width: 100%" :border="true"
              :header-cell-style="{background: '#eef1f6'}">
        <el-table-column prop="field_chinese" label="中文名" width="150" align="center"/>
        <el-table-column prop="field_name" label="字段名称" width="150" align="center"/>
        <el-table-column prop="type" label="数据类型" width="100" align="center"/>
        <el-table-column prop="default" label="默认值" width="100" align="center"/>
        <el-table-column prop="category" label="数据分类" width="100" align="center"/>
        <el-table-column prop="sensitivity_level" label="敏感级别" width="100" align="center"/>
        <el-table-column prop="describe" label="描述" align="center"/>
    </el-table>
</div>

同样使用之前的边样式,这不过这里有表头,表头是没有背景色的,我们要使用header-cell-style来绑定css样式,最终实现如下图:

其他

上面的基本信息和字段结构,是比较典型的两种table的应用,后面的数据情况、存储规则、清理策略三个table,其实现方式都是围绕着上面实现的,所以这里就不写了,直接将最后的效果图发出来。

timeline

为什么要用timeline,因为元数据展示页面通常很长,所以我想实现一个类似于导航的功能,然后觉得timeline 锚点可以实现,所转移这里就做了一个尝试。

我从ELement Plus官网直接复制的timeline代码。

代码语言:html复制
<el-timeline style="max-width: 600px">
  <el-timeline-item
          v-for="(activity, index) in activities"
          :key="index"
          :icon="activity.icon"
          :type="activity.type"
          :color="activity.color"
          :size="activity.size"
          :hollow="activity.hollow"
          :timestamp="activity.timestamp"
          hide-timestamp="true"
  >

      {{ activity.content }}

  </el-timeline-item>
</el-timeline>

生成的timeline效果如下:

发现一个问题,就是我想将timeline的文字部分放在左侧,但是默认的是右侧,所以这一部分需要使用css来调整。

代码语言:css复制
.metadata-timeline {
    width: 15%;
    height: 100%;

    & .el-timeline {
        margin-left: 177px;
        margin-top: 120px;
    }

    & :deep(.el-timeline-item__wrapper) {
        left: -120px;
        top: -5px;
    }
}

因为css定义在了scoped中,这里使用:deep实现样式穿透,利用left定位元素来控制文字位置。

然后将Timeline渲染的数据activities修改为元数据页面的table信息。

最后使用el-affix固钉组件,让页面在滚动动时timeline能固定在一个位置。

最终的效果可以将timeline中的节点设计为锚点,点击timeline的元素就可以跳转到对应的锚点上。

TencentDB表结构设计

在前端开发完之后,就要开发后端服务。这里需要根据前端渲染需要的字段进行表设计。这里先新建数据治理的governance数据。

代码语言:sql复制
create database governance default charset=utf8;

表设计

在元数据页面的表格中,除了字段结构展示需要的字段外,其他的字段我设计成了governance_metadata_manager_table_info表。

代码语言:sql复制
create table governance_metadata_manager_table_info (
    table_name varchar(50) not null primary key,
    table_name_chinese varchar(50) not null,
    table_describe varchar(50) not null,
    table_tags varchar(30) not null,
    datasource varchar(50) not null,
    table_schema varchar(50) not null,
    topic varchar(50) not null,
    renew_time varchar(50) not null,
    data_level varchar(50) not null,
    sensitivity_level varchar(50) not null,
    data_count int(20) not null,
    table_size varchar(50) not null,
    update_time varchar(50) not null,
    oldest_time varchar(50) not null,
    table_type varchar(50) not null,
    storage_mode varchar(50) not null,
    zip_type varchar(50) not null,
    zip_interval varchar(50) not null,
    saveTime varchar(50) not null,
    interval_type varchar(50) not null,
    clean_strategy varchar(50) not null,
    clean_describe varchar(50) not null
);

其中table_name作为表的主键。然后就是字段结构的数据表设计。

代码语言:sql复制
create table governance_metadata_manager_table_column_info (
    table_name varchar(50) not null,
    name varchar(50) not null,
    name_chinese varchar(50) not null,
    data_type varchar(50) not null,
    default_value varchar(50) not null,
    category varchar(50) not null,
    sensitivity_level varchar(50) not null,
    column_describe varchar(50) not null,
    primary key (table_name, name)
);

这里使用table_name和字段的name做一个一个联合主键,保证一个表中的字段名称不会被重复录入。

数据录入sql

ods_tencent_cartoon_yyyymmdd作为数据表录入到governance_metadata_manager_table_info元数据基本信息表中。

代码语言:sql复制
INSERT INTO governance_metadata_manager_table_info VALUES('ods_tencent_cartoon_yyyymmdd', 'cartoon详情数据表', 'cartoon详情数据表'
, 'ODS,日表','TencentDB for MySQL', 'aqi', '网络采集', '2024-08-120 12:00:00', '原始数据层(ODS)', '低'
, 100000, '10.23MB', '2024-08-10 12:00:00', '2024-08-09 12:00:00', '复制表', '行存储', 'gzip', '日压缩'
, '180', '日', '删除', '按照日删除');

INSERT INTO governance_metadata_manager_table_info VALUES('ods_internet_crawler_poi_yyyymmdd', '上网采集数据表', '上网采集数据表'
, 'ODS,日表','TencentDB for MySQL', 'aqi', '网络采集', '2024-08-10 12:00:00', '原始数据层(ODS)', '低'
, 100000, '10.23MB', '2024-08-10 12:00:00', '2024-08-09 12:00:00', '复制表', '行存储', 'gzip', '日压缩', '180', '日', '删除', '按照日删除');

将ods_tencent_cartoon_yyyymmdd表的字段结构录入到governance_metadata_manager_table_column_info中。

代码语言:sql复制
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'cid', 'ID', 'varchar(35)', 'NULL', '-', '低', '动漫的唯一标志');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'name', '名称', 'varchar(50)', 'NULL', '-', '低', '动漫名称');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'title', '动漫标题', 'varchar(100)', 'NULL', '-', '低', '动漫在首页的标题');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'score', '动漫评分', 'varchar(5)', 'NULL', '-', '低', '动漫评分');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'promoter_score', '推荐评分', 'varchar(20)', 'NULL', '-', '低', '推荐评分');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'evaluate_number', '推荐人数', 'varchar(30)', 'NULL', '-', '低', '推荐人数');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'type_', '动漫类型', 'varchar(4)', 'NULL', '-', '低', '动漫类型');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'year', '动漫年份', 'varchar(10)', 'NULL', '-', '低', '动漫发布的年份');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'tag_text', '会员标签', 'varchar(10)', 'NULL', '-', '低', '动漫是否有会员标签');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'main_genres', '动漫标签分类', 'varchar(20)', 'NULL', '-', '低', '动漫标签分类');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'hotval', '动漫热度', 'varchar(20)', 'NULL', '-', '低', '动漫热度');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'episode_all', '动漫剧集', 'int', 'NULL', '-', '低', '动漫剧集');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'dimension', '推荐评分比例', 'varchar(100)', 'NULL', '-', '低', '推荐评分比例');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'update_notify_desc', '剧集更新描述', 'varchar(100)', 'NULL', '-', '低', '剧集描述');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'update_time', '最新更新日期', 'varchar(20)', 'NULL', '-', '低', '最新更新日日期');
insert into governance_metadata_manager_table_column_info values ('ods_tencent_cartoon_yyyymmdd', 'cover_description', '动漫简介', 'text', 'NULL', '-', '低', '动漫简介');

TecentDB操作

在表结构设计和数据录入的sql构造完成之后,我们就要将sql在TencentDB中执行。

我是从腾讯云的CMV上连接的TencentDB,从执行SQL的响应速度来说,TencentDB比cvm上的MySQL执行速度还要快。

后台服务开发

整个数据治理平台设计的接口是超级多的。针对于数据治理展示页面,这里需要实现两种信息的查询一个是查询元数据的基本信息,一个查询元数据的字段接口信息。后台服务使用的是Springboot,首先来构建数据源。

1. DataSource

首先在application.properties中配置TencentDB的实例地址,以及数据源配置。

然后实现DataSrouce的连接池。

代码语言:java复制
@Configuration
@Slf4j
@Getter
public class MysqlDataSource {

    @Value("${spring.mysql.jdbcUrl}")
    private String jdbcUrl;

    @Value("${spring.mysql.driverClass}")
    private String driverClass;

    @Value("${spring.mysql.initialPoolSize}")
    private int initialPoolSize;

    @Value("${spring.mysql.maxPoolSize}")
    private int maxPoolSize;

    @Value("${spring.mysql.minIdle}")
    private int minIdle;

    @Value("${spring.mysql.user}")
    private String user;

    @Value("${spring.mysql.password}")
    private String password;

    @Bean
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        dataSource.setInitialSize(initialPoolSize);
        dataSource.setMaxActive(maxPoolSize);
        dataSource.setMinIdle(minIdle);
        dataSource.setValidationQuery("SELECT 1");
        return dataSource;
    }
}

接着我们开始构建mapper。

2. Mapper

新建MetadataInfoMapper对governance_metadata_manager_table_infogovernance_metadata_manager_table_column_info表数据的查询,使用table_name进行条件查询。

代码语言:java复制
@Mapper
public interface MetadataInfoMapper {
    @Select("select * from governance_metadata_manager_table_info where table_name=#{tableName}")
    MetadataInfo getMetadataInfoByTableName( String tableName);
    
    
    @Select("select * from governance_metadata_manager_table_column_info where table_name=#{tableName}")
    List<MetaDataColumn> listMetadataColumnByTableName(String tableName);
}

这里一共实现了两个查询方法,对于元数据的基本信息,mapper的返回值为MetadataInfo,这是包含所有表字段的实体类。

对于各个字段结构数据,返回的是List列表,MetaDataColumn是实体类。

相对于governance_metadata_manager_table_column_info的字段来说,在建立实体类的时候我们可以省略掉table_name字段。

3. Service

在Service中对应mapper封装了两个方法,将请求TencetnDB的元数据的结果返回。

代码语言:java复制
@Service
public class MetadataInfoService {
    @Autowired
    private MetadataInfoMapper metadataInfoMapper;

    public MetadataInfo getMetadataInfoByTableName(String tableName) {
        return metadataInfoMapper.getMetadataInfoByTableName(tableName);
    }
    
    public List<MetaDataColumn> listMetadataColumnByTableName(String tableName) {
        return metadataInfoMapper.listMetadataColumnByTableName(tableName);
    }
}

4. Controller

controller是具体的业务逻辑的实现和对外开放的接口,这里使用RestController注解,来对外返回一个json。

代码语言:java复制
@RequestMapping("metadataInfo")
@RestController
public class MetaDataInfoController {
    @Autowired
    private MetadataInfoService metadataInfoService;

    @RequestMapping(value = "/getMetadataInfoByTableName", method = RequestMethod.POST)
    @CrossOrigin(origins = "*", maxAge = 3600)
    public Map<String, Object> getMetadataInfoByTableName(String tableName) {
        Map<String, Object> result = new HashMap<>();
        MetadataInfo metadataInfo = metadataInfoService.getMetadataInfoByTableName(tableName);
        List<MetaDataColumn> metaDataColumns = metadataInfoService.listMetadataColumnByTableName(tableName);
        result.put("code", 0);
        result.put("metadataInfo", metadataInfo);
        result.put("metaDataColumns", metaDataColumns);
        return result;
    }
}

这里构造了一个getMetadataInfoByTableName的controller,入参是tableName,将mapper中查询到的metadataInfometaDataColumns返回给接口。

5. 接口测试

构造一个POST请求getMetadataInfoByTableName接口。

代码语言:shell复制
POST http://localhost:8080/metadataInfo/getMetadataInfoByTableName
Accept: */*
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded

tableName=ods_tencent_cartoon_yyyymmdd

如图,将ods_tencent_cartoon_yyyymmdd的元数据信息成功返回。

前后端交互

最后就是将从后端服务中查询到的接口数据,渲染到前端页面。在这个元数据展示页面中,上层还有一个统一的元数据全景视图,搜索、点击某一个表的视图,就会触发上面查询接口的调用,并且跳转到这个元数据展示页面渲染数据。

在前端中,使用axios异步请求后台服务,然后将元数据按照格式回填到元数据展示页面即可。

构造异步请求

利用axios模块封装一个axios.ts的请求工具。

代码语言:javascript复制
import axios from "axios";
import {AxiosRequestConfig} from "axios";

export function createAxios(baseURL: string, axiosConfig: AxiosRequestConfig) {
    const Axios = axios.create({
        baseURL: baseURL,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        responseType: 'json',
    })
    return  Axios(axiosConfig)
}

createAxios函数用来对服务器发起axios异步请求。然后我们在封装一个getMetadata函数用来传入tableName来请求对应的元数据。

代码语言:javascript复制
import {createAxios} from "/@/utils/axios";

const baseURL = "http://localhost:8080/"
export function getMetadata(tableName: String) {
  const data = "tableName="   tableName
  return createAxios(baseURL,
    {url: 'metadataInfo/getMetadataInfoByTableName', method: 'post', data: data}
  )
}

请求数据

然后在元数据展示页面的setup中,调用getMetadata发起元数据请求。

代码语言:javascript复制
const metadataInfo_web = reactive({
    code: 0,
    metadataInfo: [],
    metaDataColumns: []
});
getMetadata("ods_tencent_cartoon_yyyymmdd").then((res) => {
    metadataInfo_web.code = res.data.code
    metadataInfo_web.metadataInfo = res.data.metadataInfo
    metadataInfo_web.metaDataColumns = res.data.metaDataColumns

})
console.log(metadataInfo_web)

这里我使用响应式变量metadataInfo_web来接收后端返回元数据信息。

数据渲染

就拿字段结构的table来说,我将样例数据替换成metadataInfo_web.metaDataColumns,然后将每一列字段都替换成后端返回的数据字段。

代码语言:html复制
<el-table :data="metadataInfo_web.metaDataColumns" border style="width: 100%" :border="true"
          :header-cell-style="header_cell_style">
    <el-table-column prop="name_chinese" label="中文名" width="150" align="center"/>
    <el-table-column prop="name" label="字段名称" width="150" align="center"/>
    <el-table-column prop="data_type" label="数据类型" width="150" align="center"/>
    <el-table-column prop="default_value" label="默认值" width="100" align="center"/>
    <el-table-column prop="category" label="数据分类" width="100" align="center"/>
    <el-table-column prop="sensitivity_level" label="敏感级别" width="100" align="center"/>
    <el-table-column prop="column_describe" label="描述" align="center"/>
</el-table>

这样,后端governance_metadata_manager_table_column_info中存储的元数据字段结构信息,就被渲染成功。

结语

整篇文章的前半篇是对我对数据治理的一些概念理解,后半篇是我结合自己的工作经验,基于TecentDB对于数据治理平台的单一页面的实现。

目前数据治理成为了大数据行业的热点,如果觉得对于数据治理无从下手,可以从一些比较成熟的产品入手,去反向学习数据治理的理论。目前很多云产品已经将数据治理产品化,有兴趣的可以去搜索一下。

0 人点赞