由于最近项目的需求,仔细研究了下采用hive JDBC编码的方式来实现命令行模式执行hql语句的功能。期间遇到了不少问题,并一一进行了分析解决。但是时间匆忙,本人并未能将遇到的问题逐一记录在案。凭借零零稀稀的记忆希望将这些问题和经验进行总结以备后用。
项目中有个需求就是实现通过hql条件查询语句查询出hive外部分区表中的数据,并将这些数据保存到本地文件中。直接贴出查询的主要类似代码如下:
String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
Connection con = DriverManager.getConnection("jdbc:hive://localhost:10000/default", "", "");
Statement stmt = con.createStatement();
ResultSet rs=stmt.executeQuery("select * from mytable limit 10");
while(rs.next()){
System.out.println(rs.getString(0));//第一列为String类型数据
}
但是在运行代码时会出现异常,提示如下:
java.sql.SQLException: java.lang.ArrayIndexOutOfBoundsException: -1
报的错为数组越界异常(奇怪!以前在普通hive表中采用这种方式获取列值时没出现这种异常。),百思不得其解。尝试使用ResultSet的其他靠谱点的get方法获取第一列的值,依旧报数组越界错或者方法不支持错,看来hive的jdbc方式并未实现所有的ResultSet方法。
最后将出现异常的那行做了下修改,采用rs的getString方法调用列名参数,结果成功了。修改后的代码如下所示:
String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
Connection con = DriverManager.getConnection("jdbc:hive://localhost:10000/default", "", "");
Statement stmt = con.createStatement();
ResultSet rs=stmt.executeQuery("select * from mytable limit 10");
ResultSetMetaData rsmd = rs.getMetaData();
int count=rsmd.getColumnCount();
String[] name=new String[count];
for(int i=0;i<count;i++)
name[i]=rsmd.getColumnName(i+1);
while(rs.next()){
//System.out.println(rs.getString(0));
for(int i=0;i<count;i++)
System.out.print(rs.getString(name[i])+",");
System.out.println();
}
总结:在hive 的JDBC编码方式实现hql语句功能中,ResultSet的get+类型方法可能并不总能支持传递索引参数,这时我们得考虑换种思路,采用传递列名的方式获取值。