HBase的javaAPI操作——DDL和DML
1、先定义Admin和Connection对象
DDL操作需要Admin,DML操作需要Connection。
因为client连接HMaster和HRegionserver都是通过zookeeper,所以只要连接zookeeper就可以访问两者。
public static Connection connection; public static Admin admin; static{ try { //1、获取配置 Configuration conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "server001,server002,server003"); //端口可以不配,默认就是2181 conf.set("hbase.zookeeper.property.clientPort", "2181"); //2、获取连接对象 connection = ConnectionFactory.createConnection(conf); //3、获取Admin对象 admin = connection.getAdmin(); //HBaseAdmin admin = new HBaseAdmin(conf);(已过时) } catch (IOException e) { e.printStackTrace(); } }
再定义一个资源的关闭方法
private static void close(){ //关闭Admin if (admin != null){ try { admin.close(); } catch (IOException e) { e.printStackTrace(); } } //关闭连接 if (connection != null){ try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } }
这里注意一点,在执行时如果卡住或是报超时,在hosts配置zk的ip和主机名。
192.168.**.*** server001 192.168.**.*** server002 192.168.**.*** server003
2、DDL操作
检查表是否存在、创建表、删除表、创建命名空间
/** * 1、判断表是否存在 */ public static boolean isTableExist(String tableName) throws IOException { return admin.tableExists(TableName.valueOf(tableName)); } /** * 2、创建表 */ public static void createTable(String tableName,String... cfs) throws IOException { //1、至少定义一个列族 if (cfs.length == 0){ System.out.println("列族不能为空"); return; } //2、校验表是否已存在 if (isTableExist(tableName)){ System.out.println("该表已存在"); return; } //3、创建表描述器 HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf(tableName)); //4、添加列族定义 for (String cf : cfs) { //定义列族描述器 HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(cf); hTableDescriptor.addFamily(hColumnDescriptor); } //5、创建表 admin.createTable(hTableDescriptor); } /** * 3、删除表 */ public static void deleteTable(String tableName) throws IOException { //1、判断表是否存在 if (!isTableExist(tableName)){ System.out.println("表不存在"); return; } //2、将表下线 admin.disableTable(TableName.valueOf(tableName)); //3、删除表 admin.deleteTable(TableName.valueOf(tableName)); } /** * 4、创建命名空间 */ public static void createNamespace(String namespace){ //1、创建命名空间装饰器 NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(namespace).build(); try { //2、创建命名空间 admin.createNamespace(namespaceDescriptor); } //通过捕获异常来处理命名空间已存在 catch (NamespaceExistException e){ System.out.println(namespace+"命名空间已存在"); } catch (IOException e) { e.printStackTrace(); } }
3、DML操作
插入数据、查询数据-分为get和scan、删除数据(较为复杂)
/** * 5、向表中插入数据 */ public static void putData(String tableName,String rowKey,String cf,String cn,String value) throws IOException { //1、获取表对象 Table table = connection.getTable(TableName.valueOf(tableName)); //2、创建Put对象 Put put = new Put(Bytes.toBytes(rowKey)); put.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn),Bytes.toBytes(value)); //在同一个rowKey中插入多条数据可以再 put.addColumn(***); //3、插入数据,批量插入可以用 table.put(List<Put>) table.put(put); //关闭表连接 table.close(); } /** * 6、查询数据(get方式) */ public static void queryDataByGet(String tableName,String rowKey,String cf,String cn) throws IOException { //1、获取表对象 Table table = connection.getTable(TableName.valueOf(tableName)); //2、创建Get对象 Get get = new Get(Bytes.toBytes(rowKey)); //2.1、指定列族 //get.addFamily(Bytes.toBytes(cf)); //2.2、指定列族和列 //get.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn)); //2.3、指定要查询的版本(版本指定了系统最多给用户保存几个版本的数据) //get.setMaxVersions(2); //3、查询数据 Result result = table.get(get); //4、解析result获取数据,一个rowKey对应多个Cell for (Cell cell : result.rawCells()) { //列族 String family = Bytes.toString(CellUtil.cloneFamily(cell)); //列 String column = Bytes.toString(CellUtil.cloneQualifier(cell)); //值 String value = Bytes.toString(CellUtil.cloneValue(cell)); //时间戳 long time = cell.getTimestamp(); System.out.println("列族:"+family+",列:"+column+",值:"+value+",时间:"+time); } //5、关闭表连接 table.close(); } /** * 7、查询数据(scan方式) */ public static void queryDataByScan(String tableName) throws IOException { //1、获取表对象 Table table = connection.getTable(TableName.valueOf(tableName)); //2、创建Scan对象 Scan scan = new Scan(); //2.1、可以传入rowKey范围,左闭右开的 //Scan scan = new Scan(Bytes.toBytes("1001"),Bytes.toBytes("1003")); //2.2、也可以传入Filter过滤器 //3、扫描表 ResultScanner resultScanner = table.getScanner(scan); //4、resultScanner分批获取数据 for(Result result : resultScanner){ //4、解析result获取数据,一个rowKey对应多个Cell for (Cell cell : result.rawCells()) { //列族 String family = Bytes.toString(CellUtil.cloneFamily(cell)); //列 String column = Bytes.toString(CellUtil.cloneQualifier(cell)); //值 String value = Bytes.toString(CellUtil.cloneValue(cell)); //时间戳 long time = cell.getTimestamp(); System.out.println("列族:"+family+",列:"+column+",值:"+value+",时间:"+time); } } //5、关闭表连接 table.close(); } /** * 8、删除数据 */ public static void deleteData(String tableName,String rowKey,String cf,String cn) throws IOException { //1、获取表对象 Table table = connection.getTable(TableName.valueOf(tableName)); //2、创建Delete对象(只传rowKey相当于命令行中的deleteall) Delete delete = new Delete(Bytes.toBytes(rowKey)); //2.1、删除指定列的所有版本 //delete.addColumns(Bytes.toBytes(cf),Bytes.toBytes(cn)); //2.2、删除指定列的最新一个版本(其实是先获取最先版本数据,然后给该条数据加删除标记) //delete.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn)); //2.3、带时间戳删除指定列的所有版本(小于等于指定时间戳的数据都会被删除) //delete.addColumns(Bytes.toBytes(cf),Bytes.toBytes(cn),System.currentTimeMillis()); //2.4、删除指定版本的指定列(也就是时间戳相等的会被删除) //delete.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn),System.currentTimeMillis()); //2.5、删除指定列族(删除多版本,这个也可以传时间戳,也是小于等于的关系) //delete.addFamily(Bytes.toBytes(cf)); //3、删除数据 table.delete(delete); //5、关闭表连接 table.close(); }
其他的操作就不多说了,很好理解,这里说两个:
(1)scan方式获取数据
new Scan()有三个构造方法
获得结果 ResultScanner resultScanner = table.getSacnner(scan)。这里并不是返回一个 Result[] 数组,而是返回一个结果迭代器,分批返回查询结果(一般默认500条),因为HBase面向大数据,一次返回大量数据可能存在将内存打满的风险。
(2)删除数据delete(注意所谓删除只是添加一个删除标记)
delete其实也是put,只不过put进去的是一个删除标记,查看源码可知最终走到相同的代码。这里结合命令行操作来分析
• 先看下命令行操作:
命令行操作如果是多版本数据存储,会将所有版本数据都删除。这里再说下三种删除标记
Delete:只对某一个版本生效(即只对指定时间戳生效,等于的关系),只在API中会出现
DeleteColumn:对多个版本生效(小于等于的关系),作用于列
DeleteFamily:对多个版本生效(小于等于的关系),作用于整个列族
• 再来看API操作