大家好,我是代码搬运工。最近在利用FlinkSQL进行开发连接Hive数据库的时候遇到了一些小问题,接下来分享给大家以免以后踩坑。
在一个项目中我主要利用FlinkSQL来连接Hive数据库并执行Insert动态插入语句来关联设备信息,话不多说我们直接开始。
maven的依赖如下
org.slf4j
slf4j-log4j12
1.7.15
org.apache.flink
flink-table-api-java-bridge_2.12
1.12.2
org.apache.flink
flink-table-api-java
${flink.version}
org.apache.flink
flink-table-common
${flink.version}
org.apache.flink
flink-connector-hive_2.12
${flink.version}
org.apache.hadoop
hadoop-common
2.8.1
javax.xml.bind
jaxb-api
2.2.11
org.apache.hive
hive-exec
3.1.2
log4j-api
org.apache.logging.log4j
log4j
log4j
log4j-core
org.apache.logging.log4j
log4j-slf4j-impl
org.apache.logging.log4j
slf4j-api
org.slf4j
org.apache.hive
hive-serde
${hive.version}
log4j-api
org.apache.logging.log4j
log4j-core
org.apache.logging.log4j
log4j-slf4j-impl
org.apache.logging.log4j
slf4j-api
org.slf4j
org.apache.hive
hive-jdbc
${hive.version}
slf4j-log4j12
org.slf4j
log4j-slf4j-impl
org.apache.logging.log4j
log4j-web
org.apache.logging.log4j
log4j-core
org.apache.logging.log4j
log4j-api
org.apache.logging.log4j
log4j-1.2-api
org.apache.logging.log4j
netty-all
io.netty
hive-common
org.apache.hive
parquet-hadoop-bundle
org.apache.parquet
xerces
xercesImpl
hbase-client
org.apache.hbase
curator-framework
org.apache.curator
zookeeper
org.apache.zookeeper
slf4j-api
org.slf4j
httpcore
org.apache.httpcomponents
httpclient
org.apache.httpcomponents
commons-cli
commons-cli
commons-compress
org.apache.commons
commons-lang
commons-lang
guava
com.google.guava
gson
com.google.code.gson
avro
org.apache.avro
hbase-common
org.apache.hbase
hbase-hadoop2-compat
org.apache.hbase
hbase-server
org.apache.hbase
tephra-hbase-compat-1.0
co.cask.tephra
hbase-hadoop-compat
org.apache.hbase
log4j
log4j
!注意,这里我们要使用阿里的Blanner 我在这里踩了巨坑,一定要用阿里的Blanner才可以执行动态insert
因为Flink是流式处理,
如果我们构建table的环境是流式环境的话,数据是源源不断得输入进来。如下所示
// 构建运行流处理的运行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 构建table环境
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
这样的话我们执行动态操作的时候,例如 Insert intoXXXX Select * from XXX等语句是会报错误的,Hive Table SInk是不支持这样的。
我们查看源码可知。
Hive Table的INSERT只支持带有"+I"的数据,不允许带有-U和+U就是会改变的数据。
那怎么解决呢,不可能我想写个动态sql都不行吧,晕。。。。。
还好国内阿里进行了FlinkSQL优化,解决方法是利用阿里的BlinkPlanner来构建表环境,阿里已经内部帮你优化好了。
//使用阿里的Planner
EnvironmentSettings settings = EnvironmentSettings.newInstance().useBlinkPlanner().inBatchMode().build();
// 构建table环境
TableEnvironment tableEnv = TableEnvironment.create(settings);
//TODO 设置env的checkpoint等其他信息
//设置方言 不同数据库的语句有差别
tableEnv.getConfig().setSqlDialect(SqlDialect.HIVE);
构建好表环境后我们直接利用HiveCatalog来连接Hive数据库(里面我只是举例子,公司里一般写在常量里,直接调用就行,在公司这样写代码不被骂死我都服你)
//构造hive catalog 直接调用hiveconstans就可以
// Catalog名称,定义一个唯一的名称表示
String NAME="myhive";
// 默认Hive数据库名称
String DEFAULTDATABASE="lwtest";
//hive-site.xml路径 运行Flink的Linux目录下
String HIVECONFDIRPATH="/etc/hive/conf";
//hive版本
String VERSION="3.1.2";
HiveCatalog myHive=new HiveCatalog(NAME, DEFAULTDATABASE,HIVECONFDIRPATH, VERSION);
//注册指定名字的catalog
tableEnv.registerCatalog("myhive",myHive);
//使用上面注册的catalog
tableEnv.useCatalog("myhive");
然后我们就可以写自己的sql代码啦
//执行逻辑
Table tableResult = tableEnv.sqlQuery(sql);
//获取的结果直接打印
tableResult1.execute().print();
//获取结果的迭代器,可以循环迭代器获取结果
CloseableIterator<Row> rows = tableResult.execute().collect();
//利用executeSql执行插入更新代码
//例如insert into table xxxx select * from xxxx;
TableResult tableResult1 = tableEnv.executeSql(sql);
调用executeSql不需要调用execute,如果里面有datastream api就需要execute
完整代码如下
//使用阿里的Planner
EnvironmentSettings settings = EnvironmentSettings.newInstance().useBlinkPlanner().inBatchMode().build();
// 构建table环境
TableEnvironment tableEnv = TableEnvironment.create(settings);
//TODO 设置env的checkpoint等其他信息
//设置方言 不同数据库的语句有差别
tableEnv.getConfig().setSqlDialect(SqlDialect.HIVE);
//构造hive catalog 直接调用hiveconstans就可以
// Catalog名称,定义一个唯一的名称表示
String NAME="myhive";
// 默认Hive数据库名称
String DEFAULTDATABASE="lwtest";
//hive-site.xml路径 运行Flink的Linux目录下
String HIVECONFDIRPATH="/etc/hive/conf";
//hive版本
String VERSION="3.1.2";
HiveCatalog myHive=new HiveCatalog(NAME, DEFAULTDATABASE,HIVECONFDIRPATH, VERSION);
//注册指定名字的catalog
tableEnv.registerCatalog("myhive",myHive);
//使用上面注册的catalog
tableEnv.useCatalog("myhive");
// 执行逻辑
String sql="select * from xxxx";
Table tableResult1 = tableEnv.sqlQuery(sql);
tableResult1.execute().print();
//获取结果的迭代器,可以循环迭代器获取结果
CloseableIterator<Row> rows = tableResult1.execute().collect();
//执行executeSql 插入或更新数据库
String executeSql="insert into table xxxx select * from xxxx";
TableResult tableResult6 = tableEnv.executeSql(executeSql);