- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
基于传统关系型数据库的稳定性,还是有很多企业将数据存储在关系型数据库中;早期由于工具的缺乏,Hadoop与传统数据库之间的数据传输非常困难。基于前两个方面的考虑,需要一个在传统关系型数据库和Hadoop之间进行数据传输的项目,Sqoop应运而生。
Sqoop是一个用于Hadoop和结构化数据存储(如关系型数据库)之间进行高效传输大批量数据的工具。它包括以下两个方面:
常见数据库开源工具:
Sqoop的核心设计思想是利用MapReduce加快数据传输速度。也就是说Sqoop的导入和导出功能是通过基于Map Task(只有map)的MapReduce作业实现的。所以它是一种批处理方式进行数据传输,难以实现实时的数据进行导入和导出。
官网介绍:
Apache Sqoop™ is a tool designed for efficiently transferring bulk
data between Apache Hadoop and structured datastores such as relational databases.
Sqoop结构图:
主要执行操作
MysqlHDFSHiveHBaseimportimportimportexportexportMysqlHDFSHiveHBase
sqoop的重要的几个关键词
注意:在安装sqoop之前要配置好本机的Java环境和Hadoop环境
先把spoop的安装包sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz
拷贝在系统目录下的 /root/soft下面
2.1、解压配置环境变量
# 解压tar.gz包
[root@master local] tar -zxvf /root/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /usr/local/
#把sqoop的安装路径修改为sqoop,方便以后配置和调用
[root@master local]# mv sqoop-1.4.7.bin__hadoop-2.6.0 sqoop
[root@master sqoop]# vim /etc/profile
# 追加内容如下:
export SQOOP_HOME=/usr/local/sqoop
export PATH=$SQOOP_HOME/bin:$PATH
2.2、新建配置文件
[root@master sqoop] mv ./conf/sqoop-env-template.sh ./conf/sqoop-env.sh
2.3、修改配置文件
配置文件:
[root@master sqoop] vim ./conf/sqoop-env.sh
按照本系统实际安装的Hadoop系列目录配置好下面的路径:
export HADOOP_COMMON_HOME=/usr/local/hadoop
export HADOOP_MAPRED_HOME=/usr/local/hadoop
export HIVE_HOME=/usr/local/hive
export ZOOCFGDIR=/usr/local/zookeeper
2.4、拷贝mysql驱动
因为我们现在通过JDBC让Mysql和HDFS等进行数据的导入导出,所以我们先必须把JDBC的驱动包拷贝到sqoop/lib
路径下,如下
[root@master sqoop] cp /root/mysql-connector-java-5.1.18.jar ./lib/
2.5、验证安装:
#查看sqoop的版本
[root@master sqoop] sqoop version
通过sqoop加不同参数可以执行导入导出,通过sqoop help
可以查看常见的命令行
#常见sqoop参数
[root@master sqoop] sqoop help
codegen Generate code to interact with database records
create-hive-table Import a table definition into Hive
eval Evaluate a SQL statement and display the results
export Export an HDFS directory to a database table #导出
help List available commands
import Import a table from a database to HDFS #导入
import-all-tables Import tables from a database to HDFS
import-mainframe Import mainframe datasets to HDFS
list-databases List available databases on a server
list-tables List available tables in a database
version Display version information
Sqoop运行的时候不需要启动后台进程,直接执行sqoop
命令加参数即可.简单举例如下:
# #通过参数用下面查看数据库
[root@master sqoop] sqoop list-databases --connect jdbc:mysql://node2:3306 --username root --password 123123;
在执行sqoop命令时,如果每次执行的命令都相似,那么把相同的参数可以抽取出来,放在一个文本文件中,把执行时的参数加入到这个文本文件为参数即可. 这个文本文件可以用--options-file
来指定,平时可以用定时任务来执行这个脚本,避免每次手工操作.
把3.2章节中命令中的jdbc连接的参数一般是不变的,可以把它抽取出来放在一个文件中/.../sqoop/config.conf
,如下:
list-databases
--connect
jdbc:mysql://localhost:3306
--username
root
--password
123123
那么上面的执行的命令就可以变为:
[root@master sqoop] bin/sqoop --options-file config.conf
为了让配置文件config.txt的可读性更强,可以加入空行和注释,不会影响文件内容的读取,如下:
# 指令: 列出mysql中的所有数据库
list-databases
# 指定连接字符串
--connect
jdbc:mysql://localhost:3306
--username
root
--password
123123
import是从关系数据库导入到Hadoop,下面是一些通用参数介绍:
如下:
Argument | Description |
---|---|
–connect | 指定JDBC连接字符串 |
--connection-manager |
指定连接管理类 |
--driver |
指定连接的驱动程序 |
-P |
从控制台读入密码(可以防止密码显示中控制台) |
–password | 指定访问数据库的密码 |
–username | 指定访问数据库的用户名 |
3.4.1.1、连接数据库
sqoop的设计就是把数据库数据导入HDFS,所以必须指定连接字符串才能访问数据库,这个连接字符串类似于URL,这个连接字符串通过--connect
参数指定,它描述了连接的数据库地址和具体的连接数据库,譬如:
#指定连接的服务器地址是database.example.com ,要连接的数据库是employees
[root@master sqoop] sqoop import --connect jdbc:mysql://database.example.com/employees
上面连接命令只是指定数据库,默认情况下数据库都是需要用户名和参数的,在这里可以用--username
和--password
来指定,譬如:
#指定用户名和密码来连接数据库
[root@master sqoop] sqoop import --connect jdbc:mysql://localhost:3306/mysql --username root --password 123123;
3.4.1.2、查看数据库
在Sqoop中,可以通过list-databases
参数来查看mysql的数据库,这样在导入之前可以得到所有的数据库的名字,具体案例如下:
# 列出所有数据库
[root@master sqoop] bin/sqoop list-databases --connect jdbc:mysql://localhost:3306 --username root --password 123123;
3.4.1.3、查看所有表
在得到所有数据库的名字后,也可以查看当前数据库中的所有表,可以使用 list-tables
参数来进行查看,查看的时候在url连接中一定要指定数据库的名字.
# 列出数据库中所有表
[root@master sqoop] bin/sqoop list-tables --connect jdbc:mysql://node2:3306/qfdb --username root --password 123123;
常见Import的控制参数有如下几个:
Argument | Description |
---|---|
--append |
通过追加的方式导入到HDFS |
--as-avrodatafile |
导入为 Avro Data 文件格式 |
--as-sequencefile |
导入为 SequenceFiles文件格式 |
--as-textfile |
导入为文本格式 (默认值) |
--as-parquetfile |
导入为 Parquet 文件格式 |
--columns |
指定要导入的列 |
--delete-target-dir |
如果目标文件夹存在,则删除 |
--fetch-size |
一次从数据库读取的数量大小 |
-m,--num-mappers |
n 用来指定map tasks的数量,用来做并行导入 |
-e,--query |
指定要查询的SQL语句 |
--split-by |
用来指定分片的列 |
--table |
需要导入的表名 |
--target-dir |
HDFS 的目标文件夹 |
--where |
用来指定导入数据的where条件 |
-z,--compress |
是否要压缩 |
--compression-codec |
使用Hadoop压缩 (默认是 gzip) |
3.4.2.1、指定表导入
数据准备
在本地mysql数据库中新建一个qfdb
数据库,sql代码在data/qfdb.sql
中,如下:
CREATE TABLE emp(
empno INT primary key,
ename VARCHAR(50),
job VARCHAR(50),
mgr INT,
hiredate DATE,
sal DECIMAL(7,2),
comm decimal(7,2),
deptno INT
) ;
INSERT INTO emp values(7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO emp values(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
INSERT INTO emp values(7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);
INSERT INTO emp values(7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20);
INSERT INTO emp values(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30);
INSERT INTO emp values(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30);
INSERT INTO emp values(7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10);
INSERT INTO emp values(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000,NULL,20);
INSERT INTO emp values(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
INSERT INTO emp values(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30);
INSERT INTO emp values(7876,'ADAMS','CLERK',7788,'1987-05-23',1100,NULL,20);
INSERT INTO emp values(7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30);
INSERT INTO emp values(7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20);
INSERT INTO emp values(7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);
sqoop的典型导入都是把关系数据库中的表导入到HDFS中,使用--table
参数可以指定具体的表导入到hdfs,譬如用 --table emp
,默认情况下是全部字段导入.如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--table emp \
--target-dir hdfs://master:9000/sqoopdata/emp
--delete-target-dir
可以快速使用hdfs的命令查询结果
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*
3.4.2.2、指定列导入
如果想导入某几列,可以使用 --columns
,如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--table emp \
--columns 'empno,mgr' \
--target-dir hdfs://master:9000/sqoopdata/emp \
--delete-target-dir
可以使用下面hdfs命令快速查看结果
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*
3.4.2.3、指定条件导入
在导入表的时候,也可以通过指定where条件来导入,具体参数使用 --where
,譬如要导入员工号大于7800的记录,可以用下面参数:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--table emp \
--columns 'empno,mgr' \
--where 'empno>7800' \
--target-dir hdfs://master:9000/sqoopdata/5 \
--delete-target-dir
用命令查询结果:
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*
结果如下:
7839,null
7844,7698
7876,7788
7900,7698
7902,7566
7934,7782
3.4.2.4、指定Sql导入
上面的可以通过表,字段,条件进行导入,但是还不够灵活,其实sqoop还可以通过自定义的sql来进行导入,可以通过--query
参数来进行导入,这样就最大化的用到了Sql的灵活性。如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--query 'select empno,mgr,job from emp WHERE empno>7800 and $CONDITIONS' \
--target-dir hdfs://master:9000/sqoopdata/emp \
--delete-target-dir \
--split-by empno \
-m 1
注意:在通过--query
来导入数据时,必须要指定--target-dir
如果你想通过并行的方式导入结果,每个map task需要执行sql查询语句的副本,结果会根据sqoop推测的边界条件分区。query必须包含$CONDITIONS
。这样每个scoop程序都会被替换为一个独立的条件。同时你必须指定--split-by
。分区-m 1
是指定通过一个Mapper来执行流程
查询执行结果
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*
结果如下:
7839,null,PRESIDENT
7844,7698,SALESMAN
7876,7788,CLERK
7900,7698,CLERK
7902,7566,ANALYST
7934,7782,CLERK
3.4.2.5、单双引号区别
在导入数据时,默认的字符引号是单引号,这样sqoop在解析的时候就安装字面量来解析,不会做转移:例如:
--query 'select empno,mgr,job from emp WHERE empno>7800 and $CONDITIONS' \
如果使用了双引号,那么Sqoop在解析的时候会做转义的解析,这时候就必须要加转义字符 \ 如下:
--query "select empno,mgr,job from emp WHERE empno>7800 and \$CONDITIONS" \
3.4.2.6、MySql缺主键问题
1、如果mysql的表没有主键,将会报错:
19/12/02 10:39:50 ERROR tool.ImportTool: Import
failed: No primary key could be found for table u1. Please specify one with
-- split-by or perform a sequential import with '-m 1'
解决方案:
通过 --split-by 来指定要分片的列
代码如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--query 'select empno,mgr,job from emp WHERE empno>7800 and $CONDITIONS' \
--target-dir hdfs://master:9000/sqoopdata/emp \
--delete-target-dir \
--split-by empno \
-m 1
3.4.3.1、说明
Sqoop的导入工具的主要功能是将数据上传到HDFS中的文件中。如果您有一个与HDFS
集群相关联的Hive,Sqoop
还可以通过生成和执行CREATETABLE
语句来定义Hive中的数据,从而将数据导入到Hive中。将数据导入到Hive中就像在Sqoop命令行中添加–hive-import选项。
如果Hive表已经存在,则可以指定--hive-overwrite
选项,以指示必须替换单元中的现有表。在将数据导入HDFS或省略此步骤之后,Sqoop将生成一个Hive脚本,其中包含使用Hive的类型定义列的CREATE表操作,并生成LOAD Data INPATH
语句将数据文件移动到Hive的仓库目录中。
在导入Hive之前先要配置Hadoop的Classpath才可以,否则会报类找不到错误,在/etc/profile
末尾添加如下配置:
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HIVE_HOME/lib/*
#刷新配置
source /etc/profile
3.4.3.2、参数说明
具体的参数如下:
Argument | Description |
---|---|
--hive-home |
覆盖环境配置中的$HIVE_HOME ,默认可以不配置 |
–hive-import | 指定导入数据到Hive中 |
--hive-overwrite |
覆盖当前已有的数据 |
--create-hive-table |
是否创建hive表,如果已经存在,则会失败 |
--hive-table |
设置要导入的Hive中的表名 |
3.4.3.3、实际导入案例
具体导入演示代码如下:
提示: 为了看到演示效果,可以先在Hive删除emp表
[root@master sqoop] bin/sqoop import --connect jdbc:mysql://node2:3306/qfdb \
--username root \
--password 123123 \
--table emp \
--hive-import \
--hive-overwrite \
--fields-terminated-by ',' \
-m 1
在Hive中查看表:
hive> show tables;
#结果如下:
OK
emp
可以在Hive中查看数据是否导入:
select * from emp;
#结果如下:
7369 SMITH CLERK 7902 1980-12-17 800.0 NULL 20
7499 ALLEN SALESMAN 7698 1981-02-20 1600.0 300.0 30
7521 WARD SALESMAN 7698 1981-02-22 1250.0 500.0 30
7566 JONES MANAGER 7839 1981-04-02 2975.0 NULL 20
7654 MARTIN SALESMAN 7698 1981-09-28 1250.0 1400.0 30
7698 BLAKE MANAGER 7839 1981-05-01 2850.0 NULL 30
7782 CLARK MANAGER 7839 1981-06-09 2450.0 NULL 10
7788 SCOTT ANALYST 7566 1987-04-19 3000.0 NULL 20
7839 KING PRESIDENT NULL 1981-11-17 5000.0 NULL 10
7844 TURNER SALESMAN 7698 1981-09-08 1500.0 0.0 30
7876 ADAMS CLERK 7788 1987-05-23 1100.0 NULL 20
7900 JAMES CLERK 7698 1981-12-03 950.0 NULL 30
7902 FORD ANALYST 7566 1981-12-03 3000.0 NULL 20
7934 MILLER CLERK 7782 1982-01-23 1300.0 NULL 10
案例1
表没有主键,需要指定map task的个数为1个才能执行
Sqoop导入原理:
Sqoop默认是并行的从数据库源导入数据。您可以使用-m或–num-mappers参数指定用于执行导入的map任务(并行进程)的数量。每个参数都取一个整数值,该整数值对应于要使用的并行度。默认情况下,使用四个任务。一些数据库可以通过将这个值增加到8或16来改善性能。
默认情况下,Sqoop将标识表中的主键id列用作拆分列。从数据库中检索分割列的高值和低值,map任务操作整个范围的大小均匀的组件。譬如ID的范围是0-800,那么Sqoop默认运行4个进程,通过执行 SELECT MIN(id), MAX(id) FROM emp
找出id的范围,然后把4个任务的id设置范围是(0-200),(200-400),(400-600),(600-800)
但是当一个表没有主键时,上面的切分就无法进行,sqoop导入时就会出错,这时候可以通过-m把mapper的数量设为1,只有也Mapper在运行,这时候就不需要切分,也可以避免主键不存在时候报错的问题.
#错误信息
ERROR tool.ImportTool: Import failed: No primary key could be found for table emp. Please specify one with --split-by or perform a sequential import with '-m 1'.
导入代码:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--table emp -m 1
案例2
表没有主键,使用–split-by指定执行split的字段
问题同上,如果表没有主键,那么还有个办法就是手工指定要拆分的列,通过--split-by
来指定
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--table emp \
--split-by empno \
--delete-target-dir \
--target-dir hdfs://master:9000/sqoopdata/emp
-- 出错
Caused by: java.sql.SQLException: null, message from server: "Host 'master' is not allowed to connect to this MySQL server"
解决方案:
先连接mysql:
[root@master sqoop]# mysql -uroot -p
(执行下面的语句 .:所有库下的所有表 %:任何IP地址或主机都可以连接)
mysql> GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY 'mysql' WITH GRANT OPTION;
FLUSH PRIVILEGES;
grant all privileges on . to root@"localhost" identified by "mysql" with grant option;
FLUSH PRIVILEGES;
案例3:条件导入
需要导入的数据不是全部的,而是带条件导入
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--table emp \
--split-by empno \
--where 'empno > 7777' \
--target-dir hdfs://master:9000/sqoopdata/emp
案例4:部分字段导入
:要导入的数据,不想包含全部字段,只需要部分字段
[root@master sqoop] bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \
--username root --password 123123 \
--split-by empno \
--query 'select empno,ename,job from emp where empno > 7777 and $CONDITIONS' \
--target-dir hdfs://master:9000/sqoopdata/7
案例5:将数据导入到hive中
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb --username root --password 123123 --table emp --hive-import -m 1
在Sqoop中,使用export进行导出,指的是从HDFS中导出数据到Mysql中:
1、构建mysql的表:
CREATE TABLE `u2` (
`id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `u3` (
`id` int(11) DEFAULT NULL,
`name` varchar(20) default NULL,
`age` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、HDFS导出到mysql
[root@master sqoop]# sqoop export --connect jdbc:mysql://master:3306/qfdb \
--username root \
--password root \
--table u2 \
--driver com.mysql.jdbc.Driver \
--export-dir '/1906sqoop/u2/*' \
-m 1
# 方法二:
先重新导入数据:
[root@master sqoop]# sqoop import --connect jdbc:mysql://master:3306/qfdb \
--username root \
--password root \
--query 'select id,name,age from stu where id > 6 and $CONDITIONS' \
--driver com.mysql.jdbc.Driver \
--delete-target-dir \
--target-dir '/1906sqoop/u7' \
--split-by id \
-m 1 \
--fields-terminated-by '\t' \
--null-string '\\N' \
--null-non-string '0'
导出语句:
[root@master sqoop]# sqoop export --connect jdbc:mysql://hadoop01:3306/qfdb \
--username root \
--password root \
--table u3 \
--driver com.mysql.jdbc.Driver \
--export-dir '/1906sqoop/u7/*' \
--input-fields-terminated-by '\t' \
--input-null-string '\\N' \
--input-null-non-string '\\N' \
-m 1
要注意以下问题
--export-dir
是一个hdfs中的目录,它不识别_SUCCESS文件6.1.2.1、query where方式
通过查询具体日期的方式进行导入
新建一个脚本文件
[root@hadoop01 sqoop-1.4.7] vim ./import.sh
写入以下内容:
#!/bin/bash
# yesterday=`date -d "1 days ago" "+%Y-%m-%d"`
yesterday='2022-02-01'
sqoop import --connect jdbc:mysql://master:3306/sales_source \
--username root \
--password 123123 \
--query "select * from sales_order where DATE(order_date) = '${yesterday}' and \$CONDITIONS" \
--driver com.mysql.jdbc.Driver \
--delete-target-dir \
--target-dir /user/hive/warehouse/sales_order/dt=${yesterday} \
--split-by id \
-m 1 \
--fields-terminated-by '\t' \
--null-string '\\N' \
--null-non-string '0'
通过下面hdfs可以快速查询到结果:
[root@hadoop01 sqoop-1.4.7]# hdfs dfs -cat /user/hive/warehouse/sales_order/dt=2019-01-01/pa*
6.1.2.2 increment的append方式:
#将会手动维护last-value
[root@hadoop01 sqoop-1.4.7]# sqoop import --connect jdbc:mysql://master:3306/sales_source \
--username root \
--password root \
--table sales_order \
--driver com.mysql.jdbc.Driver \
--target-dir /user/hive/warehouse/sales_order1/dt=2019-12-30 \
--split-by id \
-m 1 \
--check-column order_number \
--incremental append \
--last-value 80000 \
--fields-terminated-by '\t' \
--null-string '\\N' \
--null-non-string '0'
使用下面命令查看:
[root@hadoop01 sqoop-1.4.7]# hdfs dfs -cat /user/hive/warehouse/sales_order1/dt=2019-12-30/pa*
job的好处:
sqoop提供一系列的job语句来操作sqoop。
$ sqoop job (generic-args) (job-args) [-- [subtool-name] (subtool-args)]
$ sqoop-job (generic-args) (job-args) [-- [subtool-name] (subtool-args)]
使用方法:
usage: sqoop job [GENERIC-ARGS] [JOB-ARGS] [-- [<tool-name>] [TOOL-ARGS]]
Job management arguments:
--create <job-id> Create a new saved job
--delete <job-id> Delete a saved job
--exec <job-id> Run a saved job
--help Print usage instructions
--list List saved jobs
--meta-connect <jdbc-uri> Specify JDBC connect string for the metastore
--show <job-id> Show the parameters for a saved job
--verbose Print more information while working
列出sqoop的job:
[root@master sqoop] sqoop job --list
创建一个sqoop的job:
[root@master sqoop]# sqoop job --create job1 -- import --connect jdbc:mysql://master:3306/qfdb \
--username root \
--password root \
--table u2 \
--driver com.mysql.jdbc.Driver \
--delete-target-dir \
--target-dir '/sqoop/job/job1' \
--split-by id \
-m 1
执行sqoop的job:
#如报错json包找不到,则需要手动添加
sqoop job --exec job1
执行的时候回让输入密码:
输入该节点用户的对应的密码即可
# 1、配置客户端记住密码(sqoop-site.xml)追加
<property>
<name>sqoop.metastore.client.record.password</name>
<value>true</value>
</property>
# 2、将密码配置到hdfs的某个文件,我们指向该密码文件
说明:在创建Job时,使用--password-file参数,而且非--passoword。主要原因是在执行Job时使用--password参数将有警告,并且需要输入密码才能执行Job。当我们采用--password-file参数时,执行Job无需输入数据库密码。
[root@master sqoop]# echo -n "root" > sqoop.pwd
[root@master sqoop]# hdfs dfs -rm sqoop.pwd /input/sqoop.pwd
[root@master sqoop]# hdfs dfs -put sqoop.pwd /input
[root@master sqoop]# hdfs dfs -chmod 400 /input/sqoop.pwd
[root@master sqoop]# hdfs dfs -ls /input
-r-------- 1 hadoop supergroup 6 2018-01-15 18:38 /input/sqoop.pwd
查看sqoop的job:
[root@master sqoop] sqoop job --show sq1
删除sqoop的job:
[root@master sqoop] sqoop job --delete sq1
问题:
1、创建job报错:19/12/02 23:29:17 ERROR sqoop.Sqoop: Got exception running Sqoop: java.lang.NullPointerException
java.lang.NullPointerException
at org.json.JSONObject.<init>(JSONObject.java:144)
解决办法:
添加java-json.jar包到sqoop的lib目录中。
如果上述办法没有办法解决,请注意hcatlog的版本是否过高,过高将其hcatlog包剔除sqoop的lib目录即可。
2、报错:Caused by: java.lang.ClassNotFoundException: org.json.JSONObject
解决办法:
添加java-json.jar包到sqoop的lib目录中。
metastore服务是元数据服务,用于存储sqoop的job相关信息,将信息保存于关系型数据库中。
优点:
(1)在MySQL中创建Sqoop的元数据存储数据库 (如果有root可以用root)
create database sqoop;
create user 'sqoop'@'%' identified by 'sqoop';
grant all privileges on sqoop.* to 'sqoop'@'%';
flush privileges;
(2)配置Sqoop的元数据存储参数
在$SQOOP_HOME/conf/sqoop-site.xml
中添加以下的参数,在/code/sqoop-site.xml
也可以查阅。
sqoop.metastore.server.location:指定元数据服务器位置,初始化建表时需要。
sqoop.metastore.client.autoconnect.url:客户端自动连接的数据库的URL。
sqoop.metastore.client.autoconnect.username:连接数据库的用户名。
sqoop.metastore.client.enable.autoconnect:启用客户端自动连接数据库。
sqoop.metastore.client.record.password:在数据库中保存密码,不需要密码即可执行sqoop job脚本。
sqoop.metastore.client.autoconnect.password:连接数据库的密码。
<property>
<name>sqoop.metastore.client.enable.autoconnect</name>
<value>false</value>
<description>If true, Sqoop will connect to a local metastore
for job management when no other metastore arguments are
provided.
</description>
</property>
<property>
<name>sqoop.metastore.client.autoconnect.url</name>
<value>jdbc:mysql://192.168.10.103:3306/sqoop</value>
</property>
<property>
<name>sqoop.metastore.client.autoconnect.username</name>
<value>root</value>
</property>
<property>
<name>sqoop.metastore.client.autoconnect.password</name>
<value>123456</value>
</property>
<property>
<name>sqoop.metastore.client.record.password</name>
<value>true</value>
</property>
<property>
<name>sqoop.metastore.server.location</name>
<value>/usr/local/sqoop/sqoop-metastore/shared.db</value>
</property>
<property>
<name>sqoop.metastore.server.port</name>
<value>16000</value>
</property>
(3)重启Sqoop服务
保存配置并重启完成后,MySQL的sqoop库中有了一个名为SQOOP_ROOT的空表。
#启动:
[root@master sqoop]# sqoop metastore &
#查看进程:
[root@master sqoop]# jps
sqoop
#关闭:
[root@master sqoop]# sqoop metastore --shutdown
(4)预装载SQOOP表
insert into SQOOP_ROOT values (NULL, 'sqoop.hsqldb.job.storage.version', '0');
(5)job相关操作
[root@master sqoop]# sqoop job --list ###需要加--meta-connect
创建job:
[root@master sqoop]# sqoop job --create sq3 --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' -- import --connect jdbc:mysql://hadoop01:3306/test \
--username root \
--password root \
--table user_info \
--driver com.mysql.jdbc.Driver \
--delete-target-dir \
--target-dir '/1906sqoop/u9' \
--split-by id \
-m 1
列出job:
[root@master sqoop]# sqoop job --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' --list
执行job:
[root@master sqoop]# sqoop job --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' --exec sq3
执行job并打印详细信息:
[root@master sqoop]# sqoop job --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' --exec sq3 -verbose
此时并不会返回先前已经创建的myjob_incremental_import作业,因为此时MySQL中没有元数据信息。该命令执行完成后,MySQL的sqoop库中有了一个名为SQOOP_SESSIONS的空表,该表存储sqoop job相关信息。
(6)将表的存储引擎修改为MYISAM(如job信息存储到mysql的SQOOP_SESSIONS则不用执行如下)
alter table SQOOP_ROOT engine=myisam;
alter table SQOOP_SESSIONS engine=myisam;
因为每次执行增量抽取后都会更新last_value值,如果使用Innodb可能引起事务锁超时错误。
一次取mysq1中批量读取的数据条数。建议优化如下:
可以用这种方式转换字符串吗?我们有相同的参数,Java 做出了正确的选择。如果值是整数 - 我们调用 parseInt(value),否则如果值是 double 型 - 我们调用 parseDoubl
如果这段代码中有一个愚蠢的错误,我提前道歉,但我似乎无法解决它。我的问题是这样的,我用GCC-8(通过home-brew安装在Mac上)编译,然后在终端中执行。当使用 int do 定义变量 s &
我用 a-videosphere 制作了一个 a-scene。我尝试使用按钮启用/禁用声音,但有些想法不起作用?这是我的代码: var gargamel = 0; function
我正在使用 ISAAC 实现来生成随机整数。我需要用这些整数创建一个高斯值。首先,我需要将它们从 0 更改为 1 的 double 值。我怎样才能在Java中做到这一点?这是到目前为止我将整数转换为
我将 0x0000 到 0x01c2 范围内的十六进制值从 BLE 获取到我的手机 a 作为字符串。为了将其绘制在图表中,我必须将其转换为 double,我已经尝试过 this method但遗憾的是
我有一个父类(super class) Animal和一个子类 Dog 。在第三节课中,我有一个 List它同时接受子类型和父类(super class)型对象。 public class foo{
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我正在尝试查询我的用户的距离。我可以用这段代码做到这一点 PFGeoPoint.geoPointForCurrentLocationInBackground { (geoPoint: PFGe
考虑示例:http://jsfiddle.net/KWLu7/16/ 我正在尝试将总体重要性值计算为每个选定选择重要性的总和乘以其父标准重要性: var watch = $scope.$watch("
这个问题在这里已经有了答案: Bounding generics with 'super' keyword (6 个答案) 关闭 2 年前。 我有一个列表装饰器,它应该允许从一个列表转换到另一个列表
为什么下面的代码没有选择最近父类(super class)型的隐式 val? class A class B extends A trait TC[-T] { def show(t: T): Stri
这是我想要做的 def merge[A, B, C](eithers: Either[A,B]*)(implicit ev1: A x, x => x)) 关于scala - 推断常见的父类(s
我正在尝试从具有 double 类型列的Cassandra表中获取 double 值。我已经使用CQL3语法创建了表: CREATE TABLE data_double ( datetime
是否应该在不需要显式类型定义的情况下编译以下 this ? def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] = prefix.fol
我正在查看某人的代码,并且在创建结构时使用了 abstract type AbstractFoo end julia> struct Foo1 struct Foo2 foo_op(x::Abst
一些示例代码: public class Main { class SomeType { } class A { protected T createSome
是否可以只接受类的泛型类型的父类(super class)型? 我正在寻找的是这样的: class MyClass { public void myMethod(TS someObject
在我的代码中,我有许多 ArrayList 被传递到排序方法中。每个 ArrayList 都有不同的泛型类型,但所有这些类型都是 Sorter 的实现。排序方法旨在接受 Sorter 类型的 Arra
如果已经有人问过这个问题,请链接并关闭这个问题。 我目前正在为另一个使用起来复杂得多(并且有潜在危险)的 API 的简化 API 设计原型(prototype)。 考虑到相关的有点复杂的对象创建,我决
我正在尝试构建一个具有某些依赖项的 android 应用程序,但是其中一个导致了此错误: Illegal class file: Class module-info is missing a supe
我是一名优秀的程序员,十分优秀!