sqoop version : Sqoop 1.4.6-cdh5.15.1
mysql cron_task 數據結構大家先記住一下後面會出現很多問題:
1、從mysql 導入數據到 hive
1.1 第一次是以英文 ','爲field 分隔符,如果沒有指定 --hive-table default.xxxx,默認爲mysql的表名: cron_task
sqoop import --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --passwordhive --table cron_task --fields-terminated-by ',' --hive-import --hive-table default.cron_task_hive --hive-overwrite -m 1
整個過程都很流程,執行的也成功了
查看一下hive 表結構,發現字段都有了
hive> desc cron_task_hive;
OK
id string
cluster_name string
create_time string
cron string
cron_schedule_id string
date_number int
date_unit string
job_id string
norminal_time string
pipeline string
pipeline_id string
pipeline_ids string
start_time string
status boolean
submitted boolean
update_time string
username string
workspace_id string
Time taken: 0.059 seconds, Fetched: 18 row(s)
查詢一下數據發現,查詢id的時候所有的內容都出現了,其他字段顯示爲null
hive> select cluster_name,create_time from cron_task_hive;
OK
NULL NULL
NULL NULL
NULL NULL
NULL NULL
NULL NULL
NULL NULL
NULL NULL
NULL NULL
NULL NULL
NULL NULL
Time taken: 0.06 seconds, Fetched: 10 row(s)
hive> select id from cron_task_hive limit 1;
OK
CronTask_414473843221581824,Cluster 1,2019-07-25 17:31:05.0,0
這就很迷了~,這是爲什麼呢?
後面查看了一下數據發現有一個字段裏面存的是json String後的內容,回想起前面我們用的是英文逗號(',')作爲分隔符寫入 hive,有可能導致了字段的拆分出現了問題
存儲json String 的字段
解決:既然我們知道了問題,那我們就來解決問題吧,我們就用'\001' (如果用\001, hive會友好的轉換成\u0001)作爲分隔符,重新導入數據到hive 表,注意:開始前要先刪除hive 表,否則數據還是以前的數據用了--hive-overwrite 也不行
1.2,以'\001' 作爲分隔符
drop table cron_task_hive;
sqoop import --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --passwordhive --table cron_task --fields-terminated-by '\001' --hive-import --hive-table default.cron_task_hive --hive-overwrite -m 1
再查詢一遍,OK啦!!!!
hive> select cluster_name,create_time from cron_task;
OK
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Cluster 1 2019-07-26 06:31:05.0
Time taken: 0.071 seconds, Fetched: 10 row(s)
禍不單行,又出現了新的問題,不怕,告訴自己關關難過關關過,mysql 中的create_time 顯示的是2019-07-25 17:31:05 , 寫入 hive 中的時間 是2019-07-26 06:31:05.0,足足差了13的小時,也就是說sqoop 從mysql導入 hive數據的過程中 時間的值都差了13個 小時
參考了博客如下,解決了這個問題:
https://blog.csdn.net/weixin_43079984/article/details/89567962
https://blog.csdn.net/nwpu_geeker/article/details/80155423
時差出現的原因是 mysql 引起的,查看一下mysql 中的時區(注意:如果不是root 的權限請轉 root,要不然像我上面的hive是沒權限修改的)
在查看一下本地的時區,一般都是東八區
date -R
mysql 查詢時區命令
show VARIABLES like "%time_zone";
將SYSTEM改爲東八區
set global time_zone = '+08:00';
set time_zone = '+08:00';
flush privileges;
show VARIABLES like "%time_zone";
OK!!!!,我們再重新執行一下上面得 sqoop 腳本,發現搞掂了
查看一下hive 數據,時間數據一致了 oh yeah!!!
hive> select cluster_name,create_time from cron_task_hive;
OK
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Cluster 1 2019-07-25 17:31:05.0
Time taken: 0.071 seconds, Fetched: 10 row(s)
2、從hive 導入數據到 mysql
2.1 命令
sqoop export --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task_local --fields-terminated-by '\001' --export-dir /user/hive/warehouse/cron_task_hive
執行失敗了,發現是mysql 沒有新建這張表
mysql 新建一張表跟之前的表一樣
create table cron_task_test like cron_task_local;
新建完繼續執行上面得sqoop 語句
sqoop export --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task_local --fields-terminated-by '\001' --export-dir /user/hive/warehouse/cron_task_hive
導入成功!!!!
3、拓展
3.1 有的童鞋就有點強迫症,覺得hive 裏面存的時間值後面有個.0 想去掉,其實是屬於Timestamp 的類型格式(yyyy-mm-dd hh:mm:ss[.fffffffff]),這裏我們也可以處理 添加 import --map-column-java,--map-column-hive,export 添加 --map-column-java,注意觀察最上面的mysql 表數據結構 create_time: timestamp, norminal_time,start_time,update_time:datetime
第一次命令執行完發現 norminal_time,start_time,update_time 的值都爲空
sqoop import --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task --fields-terminated-by '\001' --hive-import --map-column-java create_time=java.sql.Timestamp,norminal_time=java.sql.Date,start_time=java.sql.Date,update_time=java.sql.Date --map-column-hive create_time=TIMESTAMP,norminal_time=TIMESTAMP,start_time=TIMESTAMP,update_time=TIMESTAMP --hive-table default.cron_task_stamp --hive-overwrite -m 1
參考了一篇博客,博主有解釋源碼,主要是說toJava(Mysql),toHive 中的字段類型映射,現在就去掉 --map-column-hive 中的norminal,start_time,update_time (https://blog.csdn.net/MuQianHuanHuoZhe/article/details/104423768)
刪除 hive table
drop table cron_task_stamp;
執行sqoop 語句
sqoop import --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task --fields-terminated-by '\001' --hive-import --map-column-java create_time=java.sql.Timestamp,norminal_time=java.sql.Date,start_time=java.sql.Date,update_time=java.sql.Date --map-column-hive create_time=TIMESTAMP --hive-table default.cron_task_stamp --hive-overwrite -m 1
查看 hive 內容,發現create_time 確實是少了.0,後面的三個字段也輸出了,不過就是少了 HH:MM:ss如果需求允許當然沒有什麼問題了(可是.......後面我執行export 的時候發現又又又出現了個error)
執行上面成功執行過的sqoop export 語句
sqoop export --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task_test --fields-terminated-by '\001' --export-dir /user/hive/warehouse/cron_task_stamp
執行失敗了......,報錯上面說要符合 yyyy-mm-dd hh:mm:ss[.fffffffff] 格式纔行,這就很奇怪了我們從hive export mysql的時候 hive 裏面只有create_time 是timestamp類型的,其他的都是string 類型的,是不是我們要寫入mysql的時候指定一下類型呢??
export mysql 指定字段類型 sqoop 語句
sqoop export --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task_test --fields-terminated-by '\001' --map-column-java create_time=java.sql.Timestamp,update_time=java.sql.Date,norminal_time=java.sql.Date,start_time=java.sql.Date --export-dir /user/hive/warehouse/cron_task_stamp
哦豁~~~,發現執行成功,看看寫入mysql的數據如何
select create_time,norminal_time,start_time,update_time from cron_task_test
發現數據都寫入成功了,就是hive 裏面的數據,後面的時分秒都用0 替代了,搞掂啦~~~
這個時候有些童鞋又有疑問了,我現在的需求是想保留數據一致,時分秒也要,那這個時候我應該怎麼辦呢?我們回顧一下上面的import 語句,我們是不是指定了java.sql.Date --map-column-java create_time=java.sql.Timestamp,norminal_time=java.sql.Date,start_time=java.sql.Date,update_time=java.sql.Date,因爲Date類型就是yyyy-mm-dd 的寫入的時候自動會把時分秒去除掉,那我們如果不指定他讓那寫入hive 的就是String類型那不就可以保留yyyy-mm-dd HH:MM:ss 了嗎?說幹就幹,抓起袖子擼一把.......
改變了hive 表cron_task_stamp 的數據結構了,如果想繼續用這這個表名,記得先刪除表哦,否則不生效,也可以用新的表面
//刪除 hive 表
drop table cron_task_stamp;
執行sqoop import 語句
sqoop import --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task --fields-terminated-by '\001' --hive-import --map-column-java create_time=java.sql.Timestamp --map-column-hive create_time=TIMESTAMP --hive-table default.cron_task_stamp --hive-overwrite -m 1
執行成功,查看hive 數據,好了時分秒都有了
執行sqoop export語句
sqoop export --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task_test --fields-terminated-by '\001' --map-column-java create_time=java.sql.Timestamp --export-dir /user/hive/warehouse/cron_task_stamp
執行的過程中發現報錯了,報主鍵衝突,後面我說update 模式的 update-key update-mode,現在先刪除table 數據,重新執行sqoop export
腳本執行成功,寫入mysql的數據正常 ,完美
這個時候又有的童靴有點奇思妙想了,寫入hive的時候原來不是沒有指定類型嘛,指定Date的話那就只有年月日,要是我把norminal_time 的類型寫成timestamp 那在hive裏是不是就不會有.0後綴了呢,那當然是能夠實現的啦,我們來實踐一下
sqoop import 腳本,執行前記得先刪hive 表
sqoop import --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task --fields-terminated-by '\001' --hive-import --map-column-java create_time=java.sql.Timestamp,norminal_time=java.sql.Timestamp --map-column-hive create_time=TIMESTAMP,norminal_time=Timestamp --hive-table default.cron_task_stamp --hive-overwrite -m 1
寫入成功,查看hive 數據,very good 這就是我想要的了 啊哈哈哈哈哈
3.2 上面我們export 的時候不是出現了一個主鍵衝突嘛,Duplicate entry 'CronTask_414473843561320448' for key 'PRIMARY'
現在我們就來解決這個問題
--update-mode有兩種模式:
一種是updateonly 只更新,也就是說只會更新mysql已有的數據,hive 新的數據不會更新到mysql
一種是allowinsert 同時滿足更新跟插入新的數據到mysql
--update-key 主鍵id,有衝突時 進行update操作
sqoop export 命令
sqoop export --connect jdbc:mysql://192.168.1.1:3306/hive --username hive --password hive --table cron_task_test --fields-terminated-by '\001' --map-column-java create_time=java.sql.Timestamp --export-dir /user/hive/warehouse/cron_task_stamp --update-key id --update-mode allowinsert
大家也可以參考這篇博客(https://blog.csdn.net/wiborgite/article/details/80958201),實操一下 這兩種模式
3.3 針對oracle 出現的問題可以參考下面這篇博客
sqoop 從oracle導數據到hive中,date型數據時分秒截斷問題
hive開啓行轉列功能:
> set hive.cli.print.header=true; // 打印列名
> set hive.cli.print.row.to.vertical=true; // 開啓行轉列功能, 前提必須開啓打印列名功能
> set hive.cli.print.row.to.vertical.num=1; // 設置每行顯示的列數
> select * from example_table where pt='2012-03-31' limit 2;
hive查看數據表結構、列類型
> desc TableName;