三、ODS层、DWD层的构建

188 阅读12分钟

代码地址

课程目标

  • 目标:自动化的ODS层与DWD层构建

  • 实现

    • 掌握Hive以及Spark中建表的语法规则
    • 实现项目开发环境的构建
    • 自己要实现所有代码注释
    • ODS层与DWD层整体运行测试成功

数仓分层

image-20210821102418366.png

  • ODS层 :原始数据层

    • 来自于Oracle中数据的采集

    • 数据存储格式:AVRO

    • ODS区分全量和增量

    • 实现

      • 数据已经采集完成

         /data/dw/ods/one_make/full_imp
         /data/dw/ods/one_make/incr_imp
        
      • step1:创建ODS层数据库:one_make_ods

      • step2:根据表在HDFS上的数据目录来创建分区表

      • step3:申明分区

  • DWD层:明细数据层

    • 来自于ODS层数据(没有做ETL处理

    • 数据存储格式:ORC

    • 不区分全量和增量的

    • 实现

      • step1:创建DWD层数据库:one_make_dwd
      • step2:创建DWD层的每一张表
      • step3:从ODS层抽取每一张表的数据写入DWD层对应的表中

Hive建表语法

  • 实施

     CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
     (
         col1Name col1Type [COMMENT col_comment],
         co21Name col2Type [COMMENT col_comment],
         co31Name col3Type [COMMENT col_comment],
         co41Name col4Type [COMMENT col_comment],
         co51Name col5Type [COMMENT col_comment],
         ……
         coN1Name colNType [COMMENT col_comment]
     ​
     )
     [PARTITIONED BY (col_name data_type ...)]
     [CLUSTERED BY (col_name...) [SORTED BY (col_name ...)] INTO N BUCKETS]
     [ROW FORMAT row_format]
         row format delimited fields terminated by 
         lines terminated by
     [STORED AS file_format]
     [LOCATION hdfs_path]
     TBLPROPERTIES
    
    • EXTERNAL:外部表类型

      • 内部表、外部表、临时表
    • PARTITIONED BY:分区表结构

      • 普通表、分区表、分桶表
    • CLUSTERED BY:分桶表结构

    • ROW FORMAT:指定分隔符

      • 列的分隔符:\001
      • 行的分隔符:\n
    • STORED AS:指定文件存储类型

      • ODS:avro
      • DWD:orc
    • LOCATION:指定表对应的HDFS上的地址

      • 默认:/user/hive/warehouse/dbdir/tbdir
    • TBLPROPERTIES:指定一些表的额外的一些特殊配置属性

Avro建表语法

  • 实施

  • 指定文件类型

    • 方式一:指定类型

       stored as avro
      
    • 方式二:指定解析类

       --解析表的文件的时候,用哪个类来解析
       ROW FORMAT SERDE
         'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
       --读取这张表的数据用哪个类来读取
       STORED AS INPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
       --写入这张表的数据用哪个类来写入
       OUTPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
      
  • 指定Schema

    • 方式一:手动定义Schema

       CREATE TABLE embedded
       COMMENT "这是表的注释"
       ROW FORMAT SERDE
         'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
       STORED AS INPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
       OUTPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
       -- TBLPROPERTIES
       TBLPROPERTIES (
         'avro.schema.literal'='{
           "namespace": "com.howdy",
           "name": "some_schema",
           "type": "record",
           "fields": [ { "name":"string1","type":"string"}]
         }'
       );
      
    • 方式二:加载Schema文件

       CREATE TABLE embedded
       COMMENT "这是表的注释"
       ROW FORMAT SERDE
         'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
       STORED as INPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
       OUTPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
       -- TBLPROPERTIES
       TBLPROPERTIES (
        'avro.schema.url'='file:///path/to/the/schema/embedded.avsc'
       );
      
  • 建表语法

    指定文件类型、指定Schema各有两种方式,两两组合应有四种建表语法,这里只给出其中常用的两种(排除了手动定义Schema的方式)

    • 方式一:指定类型和加载Schema文件

       create external table one_make_ods_test.ciss_base_areas
       comment '行政地理区域表'
       PARTITIONED BY (dt string)
       stored as avro          -- 指定类型
       location '/data/dw/ods/one_make/full_imp/ciss4.ciss_base_areas'
       TBLPROPERTIES ('avro.schema.url'='/data/dw/ods/one_make/avsc/CISS4_CISS_BASE_AREAS.avsc');
      
    • 方式二:指定解析类和加载Schema文件

       create external table one_make_ods_test.ciss_base_areas
       comment '行政地理区域表'
       PARTITIONED BY (dt string)
       ROW FORMAT SERDE        -- 指定解析类
         'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
       STORED AS INPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
       OUTPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
       location '/data/dw/ods/one_make/full_imp/ciss4.ciss_base_areas'
       TBLPROPERTIES ('avro.schema.url'='/data/dw/ods/one_make/avsc/CISS4_CISS_BASE_AREAS.avsc');
      
       -- 中文是需要变化的部分
       create external table 数据库名称.表名
       comment '表的注释'
       partitioned by
       ROW FORMAT SERDE
         'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
       STORED AS INPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
       OUTPUTFORMAT
         'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
       location '这张表在HDFS上的路径'
       TBLPROPERTIES ('这张表的Schema文件在HDFS上的路径'
       -- 创建了一个名为 ciss_base_areas 的外部表,按 dt 字段进行分区,使用 Avro 格式,数据存储在指定的 HDFS 路径,并指定了 Avro 文件位置
       -- 1. 创建外部表
       create external table: 指定创建一个外部表,数据存储在 Hive 外部,删除表时不会删除数据。
       ​
       -- 2. 表注释
       comment '行政地理区域表'
       ​
       -- 3. 分区字段
       -- PARTITIONED BY: 指定表按某个字段分区,这里是 dt 字段,类型为字符串。
       PARTITIONED BY (dt string)
       ​
       -- 4. 固定写法
       ROW FORMAT SERDE、STORED AS INPUTFORMAT、OUTPUTFORMAT
       ​
       -- 5. 数据位置
       -- location: 指定实际数据存储的位置,这里是 HDFS 中的路径。
       location '/data/dw/ods/one_make/full_imp/ciss4.ciss_base_areas'
       ​
       -- 6. 表属性
       -- TBLPROPERTIES: 设置表的属性,这里指定 Avro 数据的模式文件位置(.avsc 文件),用于描述数据的结构。
       TBLPROPERTIES ('avro.schema.url'='/data/dw/ods/one_make/avsc/CISS4_CISS_BASE_AREAS.avsc');
      

初始化Oracle、Hive连接

 # ==============todo: 1-初始化Oracle、Hive连接,读取表的名称==============#
 # 输出信息
 recordLog('ODS&DWD Building AND Load Data')
 # 定义一个分区变量:指定当前要操作的 Hive 分区的值为 20210101
 partitionVal = '20210101'
 ​
 # 调用了获取连接的工具类,构建一个 Oracle 的连接对象
 oracleConn = OracleHiveUtil.getOracleConn()
 # 调用了获取连接的工具类,构建一个 Spark 的连接对象
 hiveConn = OracleHiveUtil.getSparkHiveConn()
 ​
 # 调用文件工具类,加载 表明文件,返回存放所有表名信息的列表(全量表、增量表)
 tableList = FileUtil.readFileContent("E:\Python_DataDevelop\1、Spark离线数仓工业项目\dw\ods\meta_data\tablenames.txt")
 ​
 # 调用表名工具类,基于传递的所有表名,将增量表与全量表进行划分到不同的列表中,并返回一个存放全量表、增量表的列表
 # tableNameList[0] : 全量表
 # tableNameList[1] : 增量表
 tableNameList = TableNameUtil.getODSTableNameList(tableList)
 ​
 # ------------------测试:输出获取到的连接以及所有表名
 # print(oracleConn)
 # print(hiveConn)
 # for tbnames in tableNameList:
 #     print("---------------------")
 #     for tbname in tbnames:
 #         print(tbname)
Oracle 连接的实现方法
 def getOracleConn():
     """
     用户获取Oracle的连接对象:cx_Oracle.connect(host='', port='', username='', password='', param='')
     :return:
     """
     # 创建 Oracle 连接对象
     oracleConn = None   #构建Oracle连接对象
     try:
         ORACLE_HOST = ConfigLoader.getOracleConfig('oracleHost')            # 通过加载类,获取Oracle连接主机地址 oracle.bigdata.cn
         ORACLE_PORT = ConfigLoader.getOracleConfig('oraclePort')            # 通过加载类,获取Oracle连接端口 1521
         ORACLE_SID = ConfigLoader.getOracleConfig('oracleSID')              # 通过加载类,获取Oracle连接的SID helowin
         ORACLE_USER = ConfigLoader.getOracleConfig('oracleUName')           # 通过加载类,获取Oracle连接的用户名 ciss
         ORACLE_PASSWORD = ConfigLoader.getOracleConfig('oraclePassWord')    # 通过加载类,获取Oracle连接的密码 123456
         dsn = cx_Oracle.makedsn(ORACLE_HOST, ORACLE_PORT, ORACLE_SID)   # 构建 DSN
         oracleConn = cx_Oracle.connect(ORACLE_USER, ORACLE_PASSWORD, dsn)   # cx_Oracle 通过 用户名、密码、dsn 构建真正的 Oracle 连接
     # 异常处理
     except cx_Oracle.Error as error:
         print(error)
     # 返回 Oracle 连接
     return oracleConn
Hive 连接的实现方法
 def getSparkHiveConn():
     """
     用户获取SparkSQL的连接对象
     :return:
     """
     # 构建SparkSQL的连接对象
     sparkHiveConn = None
     try:
         SPARK_HIVE_HOST = ConfigLoader.getSparkConnHiveConfig('sparkHiveHost')          # 通过加载类,获取 Spark 连接主机地址 spark.bigdata.cn
         SPARK_HIVE_PORT = ConfigLoader.getSparkConnHiveConfig('sparkHivePort')          # 通过加载类,获取 Spark 连接端口 10001
         SPARK_HIVE_UNAME = ConfigLoader.getSparkConnHiveConfig('sparkHiveUName')        # 通过加载类,获取 Spark 连接的用户名 root
         SPARK_HIVE_PASSWORD = ConfigLoader.getSparkConnHiveConfig('sparkHivePassWord')  # 通过加载类,获取 Spark 连接的密码 123456
         # 构建 Spark 连接
         sparkHiveConn = hive.Connection(host=SPARK_HIVE_HOST, port=SPARK_HIVE_PORT, username=SPARK_HIVE_UNAME, auth='CUSTOM', password=SPARK_HIVE_PASSWORD)
     # 异常处理
     except Exception as error:
         print(error)
     # 返回 Spark 连接
     return sparkHiveConn

ODS层建库

 # ==============todo: 2-ODS层建库==============#
 # 构建一个建库建表的类的对象:实例化的时候给连接赋值(Oracle和Hive的连接实例)
 cHiveTableFromOracleTable = CHiveTableFromOracleTable(oracleConn, hiveConn)
 # 打印日志
 recordLog('ODS层创建数据库')
 # 连接实例调用创建数据库的方法:传递 ODS 层的数据库名称
 # CreateMetaCommon.ODS_NAME:'one_make_ods',ODS层 数据库的名称
 cHiveTableFromOracleTable.executeCreateDbHQL(CreateMetaCommon.ODS_NAME)
 print(f"{CreateMetaCommon.ODS_NAME}库构建成功!")
 class CHiveTableFromOracleTable:
 ​
     # 构建当前类的对象时,初始化Oracle和Hive的连接
     def __init__(self, oracleConn, hiveConn):
         self.oracleConn = oracleConn
         self.hiveConn = hiveConn
 ​
     # 创建数据库方法
     def executeCreateDbHQL(self, dbName):
         """
         根据传递的数据库名称,在Hive中创建数据库
         :param dbName: 数据库名称
         :return: None
         """
         # 构建 建库 语句
         createDbHQL = 'create database if not exists ' + dbName
         # 获取 hive 连接的游标
         cursor = self.hiveConn.cursor()
         try:
             # 游标执行 建库 语句
             cursor.execute(createDbHQL)
         # 异常处理
         except hive.Error as error:
             print(error)
         # 执行结束,最后释放游标
         finally:
             if cursor:
                 cursor.close()

ODS层建表

 # ==============todo: 3-ODS层建表==============#
 # 打印日志
 recordLog('ODS层创建全量表...')
 # 取出全量表的表名
 fullTableList = tableNameList[0]
 # 取出每张全量表的表名
 # FULL_IMP:'full_imp',ODS层 全量表存放的路径名
 for tblName in fullTableList:
     # 创建全量表:ODS层数据库名称、全量表的表名、全量表存放的路径
     cHiveTableFromOracleTable.executeCreateTableHQL(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.FULL_IMP)
 ​
 # 打印日志
 recordLog('ODS层创建增量表...')
 # 取出增量表的表名
 incrTableList = tableNameList[1]
 # INCR_IMP:'incr_imp',ODS层 增量表存放的路径名
 for tblName in incrTableList:
     # 创建增量表:ODS层数据库名称、增量表的表名、增量表存放的路径
     cHiveTableFromOracleTable.executeCreateTableHQL(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.INCR_IMP)

全量表、增量表建表

 class CHiveTableFromOracleTable:
     # 构建当前类的对象时,初始化Oracle和Hive的连接
     ...
     # 创建数据库方法
     ...
 ​
     # 执行Hive建表
     def executeCreateTableHQL(self, dbName, tableName, dynamicDir):
         """
         用于根据传递的数据库名称、表名在Hive中创建对应的表,self为当前类的实例对象
         :param dbName: 数据库名称【ODS、DWD】
         :param tableName: 表名
         :param dynamicDir: 全量或者增量【full_imp、incr_imp】
         :return: None
         """
         # 构建一个空的列表:用于拼接字符串:SQL语句
         buffer = []
         # 构建一个游标对象
         cursor = None
         try:
             # 从 Oracle 获取表的元数据:表的信息 = 表名 + 表的注释 + list[列的信息]
             tableMeta = OracleMetaUtil.getTableMeta(self.oracleConn, tableName.upper())
             # 拼接SQL:create external table if not exists one_make_ods.
             buffer.append("create external table if not exists " + dbName + ".")
             # 拼接SQL:ciss_base_areas
             buffer.append(tableName.lower())
             # 拼接SQL:列的信息,ODS层不执行
             # 拼接SQL:列的信息,DWD层用于拼接每一列的信息
             buffer = getODSStringBuffer(buffer, dbName, tableMeta)
             # 拼接SQL:如果表有注释,将表的注释拼接到建表语句中
             if tableMeta.tableComment:
                 buffer.append(" comment '" + tableMeta.tableComment + "' \n")
             # 拼接SQL:指定分区
             buffer.append(' partitioned by (dt string) ')
             # 拼接SQL:Schema的路径,文件的存储格式
             # ods > avro、dwd > orc
             buffer.append(CreateMetaCommon.getTableProperties(dbName, tableName))
             # ODS => ods,DWD => dwd
             dbFolderName = CreateMetaCommon.getDBFolderName(dbName)
             # ODS => ciss4.,DWD => 空
             userName = CreateMetaCommon.getUserNameByDBName(dbName)
             # 拼接SQL:location
             # CreateMetaCommon.getDynamicDir(dbName,dynamicDir):设置为 full_imp 还是 incr_imp
             buffer.append(" location '/data/dw/" + dbFolderName + "/one_make/" + CreateMetaCommon.getDynamicDir(dbName,dynamicDir) + "/" + userName + tableName + "'")
             # 获取 SaprkSQl 的游标
             cursor = self.hiveConn.cursor()
             # 将 buffer 列表转为字符串,并执行 SQL 语句
             cursor.execute(''.join(buffer))
             logging.warning(f'oracle表转换{dbFolderName}后的Hive DDL语句为:\n{"".join(buffer)}')
         # 异常处理
         except Exception as exception:
             print(exception)
         # 释放游标
         finally:
             if cursor:
                 cursor.close()

ODS层申明分区

 # ==============todo: 4-ODS层申明分区==============#
 recordLog('创建ods层全量表分区...')
 # 构建用于申明分区的类对象
 createHiveTablePartition = CreateHiveTablePartition(hiveConn)
 # 全量表执行44次创建分区操作
 for tblName in fullTableList:
     # 调用申明分区的方法,申明全量表的分区:ods层的数据库名称、表名、full_imp(全量表路径)、'20210101'(20分区参数)
     createHiveTablePartition.executeCPartition(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.FULL_IMP, partitionVal)
 ​
 recordLog('创建ods层增量表分区...')
 # 增量表执行57次创建分区操作
 for tblName in incrTableList:
     # 调用申明分区的方法,申明全量表的分区:ods层的数据库名称、表名、incr_imp(增量表路径)、'20210101'(20分区参数)
     createHiveTablePartition.executeCPartition(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.INCR_IMP, partitionVal)

申明分区实现的类

 class CreateHiveTablePartition(object):
 ​
     def __init__(self, hiveConn):
         self.hiveConn = hiveConn
 ​
     def executeCPartition(self, dbName, hiveTName, dynamicDir, partitionDT):
         """
         用于实现给Hive表的数据手动申明分区
         :param dbName: 数据库名称
         :param hiveTName: 表名称
         :param dynamicDir: 全量或者增量
         :param partitionDT: 分区值
         :return: None
         """
         # 构建空列表,用于拼接SQL语句
         buffer = []
         # 定义一个游标
         cursor = None
         try:
             # SQL拼接:alter table one_make_ods.
             buffer.append("alter table " + dbName + ".")
             # SQL拼接:alter table one_make_ods.表名
             buffer.append(hiveTName)
             # SQL拼接:alter table one_make_ods.表名 add if not exists partition (dt='
             buffer.append(" add if not exists partition (dt='")
             # SQL拼接:alter table one_make_ods.表名 add if not exists partition (dt='分区值
             buffer.append(partitionDT)
             # SQL拼接:alter table one_make_ods.表名 add if not exists partition (dt='分区值)
             #               location '/data/dw/ods数据库名称/onemake/全量表 或 增量表/ciss4.
             buffer.append("') location '/data/dw/" + CreateMetaCommon.getDBFolderName(dbName) +
                           "/one_make/" + CreateMetaCommon.getDynamicDir(dbName, dynamicDir) + "/ciss4.")
             # SQL拼接:...location '/data/dw/ods数据库名称/onemake/全量表 或 增量表/ciss4.表名/分区值'
             buffer.append(hiveTName)
             buffer.append("/")
             buffer.append(partitionDT)
             buffer.append("'")
             # 实例化SparkSQL游标
             cursor = self.hiveConn.cursor()
             # 执行SQL语句
             cursor.execute(''.join(buffer))
             # 输出日志
             logging.warning(f'执行创建hive\t{hiveTName}表的分区:{partitionDT},\t分区sql:\n{"".join(buffer)}')
         # 异常处理
         except Exception as e:
             print(e)
         # 释放游标
         finally:
             if cursor:
                 cursor.close()

DWD层建库

     # ==============todo: 5-DWD层建库建表==============#
     # 5.1 建库记录日志
     recordLog('DWD层创建数据库')
     # 创建DWD层数据库
     # 连接实例调用创建数据库的方法:传递 ODS 层的数据库名称
     # CreateMetaCommon.DWD_NAME:'one_make_dwd',DWD层 数据库的名称
     cHiveTableFromOracleTable.executeCreateDbHQL(CreateMetaCommon.DWD_NAME)
 class CHiveTableFromOracleTable:
     # 构建当前类的对象时,初始化Oracle和Hive的连接
     ...
 ​
     # 创建数据库方法
     def executeCreateDbHQL(self, dbName):
         """
         根据传递的数据库名称,在Hive中创建数据库
         :param dbName: 数据库名称
         :return: None
         """
         # 构建 建库 语句
         createDbHQL = 'create database if not exists ' + dbName
         # 获取 hive 连接的游标
         cursor = self.hiveConn.cursor()
         try:
             # 游标执行 建库 语句
             cursor.execute(createDbHQL)
         # 异常处理
         except hive.Error as error:
             print(error)
         # 执行结束,最后释放游标
         finally:
             if cursor:
                 cursor.close()

DWD层建表

     # ==============todo: 5-DWD层建库建表==============#
     # 5.2 建表记录日志
     recordLog('DWD层创建表...')
     # 将全量表、增量表的全部表名数据 整理到 一个列表中
     allTableName = [i for j in tableNameList for i in j]
     for tblName in allTableName:
         cHiveTableFromOracleTable.executeCreateTableHQL(CreateMetaCommon.DWD_NAME, tblName, None)

全量表、增量表建表

 class CHiveTableFromOracleTable:
     # 构建当前类的对象时,初始化Oracle和Hive的连接
     ...
     # 创建数据库方法
     ...
 ​
     # 执行Hive建表
     def executeCreateTableHQL(self, dbName, tableName, dynamicDir):
         """
         用于根据传递的数据库名称、表名在Hive中创建对应的表,self为当前类的实例对象
         :param dbName: 数据库名称【ODS、DWD】
         :param tableName: 表名
         :param dynamicDir: 全量或者增量【full_imp、incr_imp】
         :return: None
         """
         # 构建一个空的列表:用于拼接字符串:SQL语句
         buffer = []
         # 构建一个游标对象
         cursor = None
         try:
             # 从 Oracle 获取表的元数据:表的信息 = 表名 + 表的注释 + list[列的信息]
             tableMeta = OracleMetaUtil.getTableMeta(self.oracleConn, tableName.upper())
             # 拼接SQL:create external table if not exists one_make_ods.
             buffer.append("create external table if not exists " + dbName + ".")
             # 拼接SQL:ciss_base_areas
             buffer.append(tableName.lower())
             # 拼接SQL:列的信息,ODS层不执行
             # 拼接SQL:列的信息,DWD层用于拼接每一列的信息
             buffer = getODSStringBuffer(buffer, dbName, tableMeta)
             # 拼接SQL:如果表有注释,将表的注释拼接到建表语句中
             if tableMeta.tableComment:
                 buffer.append(" comment '" + tableMeta.tableComment + "' \n")
             # 拼接SQL:指定分区
             buffer.append(' partitioned by (dt string) ')
             # 拼接SQL:Schema的路径,文件的存储格式
             # ods > avro、dwd > orc
             buffer.append(CreateMetaCommon.getTableProperties(dbName, tableName))
             # ODS => ods,DWD => dwd
             dbFolderName = CreateMetaCommon.getDBFolderName(dbName)
             # ODS => ciss4.,DWD => 空
             userName = CreateMetaCommon.getUserNameByDBName(dbName)
             # 拼接SQL:location
             # CreateMetaCommon.getDynamicDir(dbName,dynamicDir):设置为 full_imp 还是 incr_imp
             buffer.append(" location '/data/dw/" + dbFolderName + "/one_make/" + CreateMetaCommon.getDynamicDir(dbName,dynamicDir) + "/" + userName + tableName + "'")
             # 获取 SaprkSQl 的游标
             cursor = self.hiveConn.cursor()
             # 将 buffer 列表转为字符串,并执行 SQL 语句
             cursor.execute(''.join(buffer))
             logging.warning(f'oracle表转换{dbFolderName}后的Hive DDL语句为:\n{"".join(buffer)}')
         # 异常处理
         except Exception as exception:
             print(exception)
         # 释放游标
         finally:
             if cursor:
                 cursor.close()

DWD层数据抽取

 # ==============todo: 6-DWD层数据抽取==============#
 # 记录日志
 recordWarnLog('DWD层加载数据,此操作将启动Spark JOB执行,请稍后...')
 for tblName in allTableName:
     recordLog(f'加载dwd层数据到{tblName}表...')
     try:
         LoadData2DWD.loadTable(oracleConn, hiveConn, tblName, partitionVal)
     except Exception as error:
         print(error)
     recordLog('完成!!!')

数据加载实现类

 def loadTable(orclConn, hiveConn, tableName, partitionValue):
     """
     加载ODS层表的数据到DWD层
     :param orclConn: Oracle连接对象
     :param hiveConn: Hive连接对象
     :param tableName: 表名
     :param partitionValue: 分区值
     :return: None
     """
     tableMeta = OracleMetaUtil.getTableMeta(orclConn, tableName.upper())
     buffer = [
         "insert overwrite table " + CreateMetaCommon.DWD_NAME + "." + tableMeta.tableName + " partition(dt=" + partitionValue + ")\n",
         "select\n"]
     # 拼接所有列名
     allColumns = ', '.join(cname for cname in tableMeta.getColumnNameList())
     buffer.append(allColumns + "\n")
     buffer.append("from " + CreateMetaCommon.ODS_NAME + "." + tableMeta.tableName + "\n")
     buffer.append("where dt='" + partitionValue + "'")
     logging.warning(f'SparkSql插入数据,sql\n{"".join(buffer).lower()}')
     # 将整个SQL语句转换为小写
     loadSQL = ''.join(buffer).lower()
     # 获取Hive连接的一个游标
     cursor = hiveConn.cursor()
     # 执行SQL语句,加载数据
     cursor.execute(loadSQL)