Apache Sqoop系列文章

1、Apache Sqoop介绍及部署
2、sqoop导入(RMDB-mysql、sybase到HDFS-hive)
3、Sqoop导出(HDFS到RMDB-mysql)
4、Sqoop job作业



本文介绍了sqoop的导出到mysql示例,其他的关系型数据库基本上差不多,仅以mysql示例介绍了导出的三种不同模式的示例。
本文前提依赖是hadoop、hive、mysql、sqoop环境可用。
本文分为2个部分,即sqoop导出介绍以及三种模式导出的详细示例。

一、Sqoop导出介绍

将数据从Hadoop生态体系导出到RDBMS数据库导出前,目标表必须存在于目标数据库中。

1、export有三种模式

  • 默认操作是从将文件中的数据使用INSERT语句插入到表中
  • 更新模式:Sqoop将生成UPDATE替换数据库中现有记录的语句
  • 调用模式:Sqoop将为每条记录创建一个存储过程调用

2、export命令语法

$ sqoop export (generic-args) (export-args)

二、使用示例

1、默认模式导出HDFS数据到mysql

默认情况下,sqoop export将每行输入记录转换成一条INSERT语句,添加到目标数据库表中。如果数据库中的表具有约束条件(例如,其值必须唯一的主键列)并且已有数据存在,则必须注意避免插入违反这些约束条件的记录。如果INSERT语句失败,导出过程将失败。此模式主要用于将记录导出到可以接收这些结果的空表中。

通常用于全表数据导出。

导出时可以是将Hive表中的全部记录或者HDFS数据(可以是全部字段也可以部分字段)导出到Mysql目标表。

1)、准备HDFS数据

本示例是使用原来hive中已经有的数据,也是从mysql中导入到hive中的数据。

文件目录
/user/hive/warehouse/test.db/person/part-m-00000

[root@server7 sqoop]# hadoop fs -cat /user/hive/warehouse/test.db/person/part-m-00000
11,测试修改go语言,30
13,NameUpdate,22
14,updatejson,23
189,再试一试,12
191,test-full-update,3333
889,zhangsanswagger2,88
892,update,189
1001,testupdate,19
1002,测试go语言,23
1013,slene,0
1014,testing,0
1015,testing,18
1016,astaxie,19
1017,alan,18
1018,chan,19

[server6:21000] test> select * from person;
Query: select * from person
Query submitted at: 2022-11-09 10:20:25 (Coordinator: http://server6:25000)
Query progress can be monitored at: http://server6:25000/query_plan?query_id=2744bd675e9d7f0b:82b2b2ff00000000
+------+------------------+------+
| id   | name             | age  |
+------+------------------+------+
| 11   | 测试修改go语言   | 30   |
| 13   | NameUpdate       | 22   |
| 14   | updatejson       | 23   |
| 189  | 再试一试         | 12   |
| 191  | test-full-update | 3333 |
| 889  | zhangsanswagger2 | 88   |
| 892  | update           | 189  |
| 1001 | testupdate       | 19   |
| 1002 | 测试go语言       | 23   |
| 1013 | slene            | 0    |
| 1014 | testing          | 0    |
| 1015 | testing          | 18   |
| 1016 | astaxie          | 19   |
| 1017 | alan             | 18   |
| 1018 | chan             | 19   |
+------+------------------+------+
Fetched 15 row(s) in 4.87s

2)、手动创建mysql中的目标表

CREATE TABLE `person2`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1019 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

3)、执行导出命令

# 需要特别注意字段间的分隔符
sqoop export  --connect "jdbc:mysql://192.168.10.44:3306/test?useUnicode=true&characterEncoding=utf-8" --username root --password rootroot \
--table person2 \
--input-fields-terminated-by ',' \
--export-dir /user/hive/warehouse/test.db/person/part-m-00000

4)、异常解决

异常一:

22/11/08 18:00:46 ERROR orm.CompilationManager: 
Could not rename /tmp/sqoop-root/compile/b0b899404dbc3644d6666aa04d69188a/person2.java 
to /opt/cloudera/parcels/CDH-6.2.1-1.cdh6.2.1.p0.1425774/lib/sqoop/lib/./person2.java. 
Error: Destination '/opt/cloudera/parcels/CDH-6.2.1-1.cdh6.2.1.p0.1425774/lib/sqoop/lib/./person2.java' already exists

解决办法:删除/opt/cloudera/parcels/CDH-6.2.1-1.cdh6.2.1.p0.1425774/lib/sqoop/lib/目录下的person2.java

异常二:

Sqoop报错ERROR tool.ExportTool: Error during export
参考网址:https://blog.csdn.net/weixin_42003671/article/details/89407945

遇到这个报错说明你的mysql和hive的字段不对应或者数据格式有出入
解决思路:

  • 第一步:完整的检查mysql和hive表的结构(字段名称和数据类型)是否一致。

  • 第二步:查看数据有没有导入?如果数据没有导入,请在检查第一步操作,可以将mysql和hive中的时间类型都改成string或varchar类型试一下。如果有导入,但是导入的数据不全或者不对。说明肯定是你的数据类型和实际的数据不一致。下面分两种情况。详见以下三步。

  • 第三步:在mysql到hive中,请务必检查你的数据中是否包含hive建表默认的换行符 \n(LINES TERMINATED BY '\n’)。如果有,则sqoop语句中加上 hive-delims-replacement 或者 hive-drop-import-delims

  • 第四步:在mysql到hive中,请务必检查你的数据中是否包含hive建表常用的字段分隔符 \t(FIELDS TERMINATED BY '\t’)。如果有,则sqoop语句中 fields-terminated-by 参数不能用 \t

  • 第五步:在hive到hive中,如果有很多空列,有时也会报如上错误,则sqoop语句中加上 input-null-string 和 input-null-non-string

5)、相关配置参数

  • –input-fields-terminated-by ‘\t’
    指定文件中的分隔符
  • –columns
    选择列并控制它们的排序。当导出数据文件和目标表字段列顺序完全一致的时候可以不写。否则以逗号为间隔选择和排列各个列。没有被包含在–columns后面列名或字段要么具备默认值,要么就允许插入空值。否则数据库会拒绝接受sqoop导出的数据,导致Sqoop作业失败
  • –export-dir 导出目录,在执行导出的时候,必须指定这个参数,同时需要具备–table或–call参数两者之一,–table是指的导出数据库当中对应的表,–call是指的某个存储过程。
  • –input-null-string --input-null-non-string
    如果没有指定第一个参数,对于字符串类型的列来说,“NULL”这个字符串就回被翻译成空值,如果没有使用第二个参数,无论是“NULL”字符串还是说空字符串也好,对于非字符串类型的字段来说,这两个类型的空串都会被翻译成空值。比如:–input-null-string “\N” --input-null-non-string “\N”

2、更新导出(updateonly模式)

1)、参数说明

  • – update-key,更新标识,即根据某个字段进行更新,例如id,可以指定多个更新标识的字段,多个字段之间用逗号分隔。
  • – updatemod,指定updateonly(默认模式),仅仅更新已存在的数据记录,不会插入新纪录。

2)、准备HDFS数据

# 在HDFS “/test/export/”目录的下创建一个文件updateonly.txt:
1201,gopal,manager,50000
1202,manisha,preader,50000
1203,kalil,php dev,30000

3)、手动创建mysql中的目标表

mysql> USE userdb;
mysql> CREATE TABLE updateonly ( 
   id INT NOT NULL PRIMARY KEY, 
   name VARCHAR(20), 
   deg VARCHAR(20),
   salary INT);

4)、先执行全部导出操作

sqoop export  --connect "jdbc:mysql://192.168.10.44:3306/test?useUnicode=true&characterEncoding=utf-8" --username root --password 888888 \
--table updateonly \
--export-dir /test/export/updateonly.txt

5)、查看此时mysql中的数据

可以发现是全量导出,全部的数据

在这里插入图片描述

6)、新增一个文件

updateonly2.txt。修改了前三条数据并且新增了一条记录。上传至/test/export/目录下

1201,gopal,manager,1212
1202,manisha,preader,1313
1203,kalil,php dev,1414
1204,allen,java,1515

7)、执行更新导出

sqoop export  --connect "jdbc:mysql://192.168.10.44:3306/test?useUnicode=true&characterEncoding=utf-8" --username root --password 8888888 \
--table updateonly \
--export-dir /test/export/updateonly2.txt \
--update-key id \
--update-mode updateonly

8)、查看最终结果

虽然导出时候的日志显示导出4条记录
但最终只进行了更新操作,没有将新增的数据插入
在这里插入图片描述

3、更新导出(allowinsert模式)

1)、参数说明

  • – update-key,更新标识,即根据某个字段进行更新,例如id,可以指定多个更新标识的字段,多个字段之间用逗号分隔。
  • – updatemod,指定allowinsert,更新已存在的数据记录,同时插入新纪录。实质上是一个insert & update的操作。

2)、准备HDFS数据

在HDFS “/test/export/”目录的下创建一个文件allowinsert_1.txt:

1201,gopal,manager,50000
1202,manisha,preader,50000
1203,kalil,php dev,30000

3)、手动创建mysql中的目标表

mysql> USE userdb;
mysql> CREATE TABLE allowinsert ( 
   id INT NOT NULL PRIMARY KEY, 
   name VARCHAR(20), 
   deg VARCHAR(20),
   salary INT);

4)、先执行全部导出操作

sqoop export  --connect "jdbc:mysql://192.168.10.44:3306/test?useUnicode=true&characterEncoding=utf-8" --username root --password 888888 \
--table allowinsert \
--export-dir /test/export/allowinsert_1.txt

5)、查看此时mysql中的数据

可以发现是全量导出,全部的数据
在这里插入图片描述

6)、新增一个文件

allowinsert_2.txt。修改了前三条数据并且新增了一条记录。上传至/test/export/目录下

1201,gopal,manager,1212
1202,manisha,preader,1313
1203,kalil,php dev,1414
1204,allen,java,1515

7)、执行更新导出

sqoop export  --connect "jdbc:mysql://192.168.10.44:3306/test?useUnicode=true&characterEncoding=utf-8" --username root --password 888888 \
--table allowinsert \
--export-dir /test/export/allowinsert_2.txt \
--update-key id \
--update-mode allowinsert

8)、查看最终结果

导出时候的日志显示导出4条记录
数据进行更新操作的同时也进行了新增的操作
在这里插入图片描述
以上完成了sqoop导出到mysql的几种示例,基本上满足日常的应用。另外,本处演示的仅仅是一次性作业,如果是定时的任务的话,可使用很多中方式来实现,比如oozie、azkaban等等有界面的管理工具。

Logo

更多推荐