学科分类

HBase的Java API操作

HBase是由Java语言开发的,它对外提供了Java API的接口。接下来,通过一个表来列举HBase常见的Java API,具体如表1所示。

表1 常见的Java API

类或接口名称 相关说明
Admin 是一个类,用于建立客户端和HBase 数据库的连接,属于org.apache.hadoop.hbase.client包
HBaseConfiguration 是一个类,用于将HBase配置添加到配置文件中,属于org.apache.hadoop.hbase包
HTableDescriptor 是一个接口,用于描述表的信息,属于org.apache.hadoop.hbase包
HColumnDescriptor 是一个类,用于描述列族的信息,属于org.apache.hadoop.hbase包
Table 是一个接口,用于实现HBase表的通信,属于org.apache.hadoop.hbase.client包
Put 是一个类,用于插入数据操作,属于org.apache.hadoop.hbase.client包
Get 是一个类,用于查询单条记录,属于org.apache.hadoop.hbase.client包
Delete 是一个类,用于删除数据,属于org.apache.hadoop.hbase.client包
Scan 是一个类,用于查询所有记录。属于org.apache.hadoop.hbase.client包
Result 是一个类,用于查询返回的单条记录结果,属于org.apache.hadoop.hbase.client包

接下来,通过Java API来操作HBase分布式数据库,包括增、删、改以及查等对数据表的操作,具体操作步骤如下:

1. 创建工程并导入依赖

创建一个名称为“spark_chapter05”的Maven项目。然后在项目spark_chapter05中配置pom.xml文件,也就是引入HBase相关的依赖和单元测试的依赖,pom.xml文件添加的内容具体如下所示:

  <!--单元测试依赖-->
  <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version>
  </dependency>
  <!--hbase客户端依赖-->
  <dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.2.1</version>
  </dependency>
  <!--hbase核心依赖-->
  <dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-common</artifactId><version>1.2.1</version>
  </dependency>

当添加完相关依赖后,HBase相关Jar包就会自动下载,成功引入依赖如图1所示。

img

​ 图1 成功引入的Jar包

  1. 创建Java类,连接集群

在项目spark_chapter05目录/src/main/java下创建一个名为com.itcast.hbase包,并在该包下创建HBaseTest.java文件,该文件用于编写Java测试类,构建Configuration和Connection对象。初始化客户端对象的具体操作步骤,如文件1所示。

文件1 HBaseTest.java

 1  import org.apache.hadoop.conf.Configuration;
 2  import org.apache.hadoop.hbase.*;
 3  import org.apache.hadoop.hbase.client.*;
 4  import org.apache.hadoop.hbase.util.Bytes;
 5  import org.junit.*;
 6  import java.util.*;
 7  //todo:HBase Api操作
 8  public class HBaseTest {
 9    //初始化Configuration对象
 10   private Configuration conf = null;
 11   //初始化连接
 12   private Connection conn = null;
 13   @Before
 14   public void init() throws Exception{
 15     //获取Configuration对象
 16     conf = HBaseConfiguration.create();
 17     //对hbase客户端来说,只需知道hbase所经过的Zookeeper集群地址即可
 18     //因为hbase的客户端找hbase读写数据完全不用经过HMaster
 19     conf.set("hbase.zookeeper.quorum",
 20           "hadoop01:2181,hadoop02:2181,hadoop03:2181");
 21     //获取连接
 22     conn = ConnectionFactory.createConnection(conf);
 23   }
 24 }

在上述代码中,第10-12行代码是初始化Configuration配置对象和Connection连接对象;第13行代码是注解@Before,用于Junit单元测试中控制程序最先执行的注解,在这里可以保证初始化init()方法在程序中是最先执行的;第16-22行代码是初始化客户端对象的初始化方法,主要是获取Configuration配置对象和Connection连接对象以及指定Zookeeper集群的地址。

3. 创建数据表

在HBaseTest.Java文件中,定义一个方法createTable(),主要用于演示创建数据表操作。具体代码如下:

 1  @Test
 2  public void createTable() throws Exception{
 3    //获取表管理器对象
 4    Admin admin = conn.getAdmin();
 5    //创建表的描述对象,并指定表名
 6    HTableDescriptor tableDescriptor =new HTableDescriptor(TableName
 7                   .valueOf("t_user_info".getBytes()));
 8    //构造第一个列族描述对象,并指定列族名
 9    HColumnDescriptor hcd1 = new HColumnDescriptor("base_info");
 10   //构造第二个列族描述对象,并指定列族名
 11   HColumnDescriptor hcd2 = new HColumnDescriptor("extra_info");
 12   //为该列族设定一个版本数量,最小为1,最大为3
 13   hcd2.setVersions(1,3);
 14   //将列族描述对象添加到表描述对象中
 15   tableDescriptor.addFamily(hcd1).addFamily(hcd2);
 16   //利用表管理器来创建表
 17   admin.createTable(tableDescriptor);
 18   //关闭
 19   admin.close();
 20   conn.close();
 21 }

在上述代码中,第4-11行代码获取HBase表管理器对象admin、创建表的描述对象tableDescriptor并指定表名为t_user_info、创建两个列族描述对象hcd1、hcd2并指定列族名分别为base_info和extra_info;第13行代码为列族hcd2指定版本数量;第15行代码将列族描述对象添加到表描述对象中;第16行代码使用表管理器来创建表;第19-20行代码关闭表管理器和连接对象,避免资源浪费。

运行createTable()方法进行测试,然后进入HBase Shell交互式页面,执行“list”命令查看数据库,具体代码如下:

hbase(main):022:0> list
TABLE
t_user_info
1 row(s) in 0.0200 seconds
=> ["t_user_info"]

在上述代码中,数据库中有一个名称为t_user_info的数据表,说明数据表创建成功。

4. 插入数据

在HBaseTest.Java文件中,定义一个testPut()方法,主要用于演示在t_user_info表中插入数据的操作。具体代码如下:

 1  @Test
 2  public void testPut() throws Exception {
 3    //创建table对象,通过table对象来添加数据
 4    Table table = conn.getTable(TableName.valueOf("t_user_info"));
 5    //创建一个集合,用于存放Put对象
 6    ArrayList<Put> puts = new ArrayList<Put>();
 7    //构建put对象(KV形式),并指定其行键 
 8    Put put01 = new Put(Bytes.toBytes("user001"));
 9    put01.addColumn(Bytes.toBytes("base_info"),Bytes.toBytes("username"),
 10                        Bytes.toBytes("zhangsan"));
 11   put01.addColumn(Bytes.toBytes("base_info"),Bytes.toBytes("password"),
 12                        Bytes.toBytes("123456"));
 13   Put put02 = new Put("user002".getBytes());
 14   put02.addColumn(Bytes.toBytes("base_info"),Bytes.toBytes("username"),
 15                            Bytes.toBytes("lisi"));
 16   put02.addColumn(Bytes.toBytes("extra_info"),Bytes.toBytes("married"),
 17                        Bytes.toBytes("false"));
 18   //把所有的put对象添加到一个集合中
 19   puts.add(put01);
 20   puts.add(put02);
 21   //提交所有的插入数据的记录
 22   table.put(puts);
 23   //关闭
 24   table.close();
 25   conn.close();
 26 }

上述代码中,第4行代码创建一个表对象table,用于插入数据;第6行代码创建一个集合puts,主要用于存放Put对象;第8-17行代码创建了Put对象,用于构建表中的行和列,这里创建了2个Put对象,并指定其行键;第19-22行代码将前面创建的8个对象添加到puts集合中,并通过表对象table提交插入数据的记录;第24-25行代码关闭表对象和连接对象,避免资源浪费。

运行testPut()方法进行测试,然后在HBase Shell交互式页面执行“scan”命令,查看数据表t_user_info中的数据,具体代码如下:

hbase(main):023:0> scan 't_user_info'
ROW     COLUMN+CELL
user001   column=base_info:password,timestamp=1545759238044,value=123456
user001    column=base_info:username, timestamp=1545759238044, value=zhangsan
user002   column=base_info:username, timestamp=1545759238044, value=lisi
user002   column=extra_info:married, timestamp=1545759238044, value=false
2 row(s) in 0.0370 seconds

5. 查看指定字段的数据

在HBaseTest.Java文件中,定义一个testGet()方法用于演示查看行键为user001的数据。具体代码如下:

 1  @Test
 2  public void testGet() throws Exception {
 3    //获取一个table对象
 4    Table table = conn.getTable(TableName.valueOf("t_user_info"));
 5    // 创建get查询参数对象,指定要获取的是哪一行
 6    Get get = new Get("user001".getBytes());
 7    //返回查询结果的数据
 8    Result result = table.get(get);
 9    //获取结果中的所有cell
 10   List<Cell> cells = result.listCells();
 11   //遍历所有的cell
 12   for(Cell cell:cells){
 13   //获取行键
 14   System.out.println("行:"+Bytes.toString(CellUtil.cloneRow(cell)));
 15   //得到列族
 16    System.out.println("列族:"+Bytes.toString(CellUtil.cloneFamily(cell)));
 17    System.out.println("列:"+Bytes.toString(CellUtil.cloneQualifier(cell)));
 18   System.out.println("值:"+Bytes.toString(CellUtil.cloneValue(cell)));
 19   }
 20   //关闭
 21   table.close();
 22   conn.close();
 23 }

上述代码中,第4行代码创建一个表对象table,并指定要查看的数据表t_user_info;第6行代码创建一个对象get,并指定要查看数据表行键为user001所有数据;第8-10行代码通过表对象table调用get()方法把行键为user001的所有数据放到集合cells中;第12-18行代码遍历打印集合cells中的所有数据;第21-22行代码关闭表对象和连接对象,避免资源浪费。

运行testGet()方法进行测试,IDEA控制台输出的内容,如图2所示。

img

​ 图2 查看数据表t_user_info中行键为user001的数据

从图2可以看出,行键为user001的数据一共有两条,一条是行键为user001、列族为base_info、列为password、值为123456的数据;另一条是行键为user001、列族为baseinfo、列为username、值为zhangsan的数据。

6. 扫描数据

在HBaseTest.Java文件中,定义一个testScan()方法用于演示扫描t_user_info表中的所有数据。具体代码如下:

 1  @Test
 2  public void testScan() throws Exception {
 3    //获取table对象
 4    Table table = conn.getTable(TableName.valueOf("t_user_info"));
 5    //创建scan对象
 6    Scan scan = new Scan();
 7    //获取查询的数据
 8    ResultScanner scanner = table.getScanner(scan);
 9    //获取ResultScanner所有数据,返回迭代器
 10   Iterator<Result> iter = scanner.iterator();
 11   //遍历迭代器
 12   while (iter.hasNext()) {
 13     //获取当前每一行结果数据
 14     Result result = iter.next();
 15     //获取当前每一行中所有的cell对象
 16     List<Cell> cells = result.listCells();
 17     //迭代所有的cell
 18     for(Cell c:cells){
 19       //获取行键
 20       byte[] rowArray = c.getRowArray();
 21       //获取列族
 22       byte[] familyArray = c.getFamilyArray();
 23       //获取列族下的列名称
 24       byte[] qualifierArray = c.getQualifierArray();
 25       //列字段的值
 26       byte[] valueArray = c.getValueArray();
 27       //打印rowArray、familyArray、qualifierArray、valueArray
 28       System.out.println("行键:"+new String(rowArray,c.getRowOffset(),
 29                           c.getRowLength()));
 30       System.out.print("列族:"+ new String(familyArray,c.getFamilyOffset(),
 31                         c.getFamilyLength()));
 32       System.out.print(" "+"列:" + new String(qualifierArray,
 33             c.getQualifierOffset(),c.getQualifierLength()));
 34       System.out.println(" " +"值:" new String(valueArray,
 35                 c.getValueOffset(), c.getValueLength()));
 36     }
 37      System.out.println("-----------------------");
 38   }
 39   //关闭 
 40   table.close();
 41   conn.close();
 42 }

上述代码中,第4行代码创建一个表对象table,并指定要查看的数据表t_user_info;第6行代码创建一个全表扫描对象scan;第8-10行代码通过表对象table调用getScanner()方法扫描表中的所有数据,并将扫描到的所有数据存放入迭代器中;第12-35行代码遍历输出迭代器中的数据;第40-41代码关闭表对象和连接对象,避免资源浪费。

运行testScan()方法进行测试,IDEA控制台输出的内容,如图3所示。

img

​ 图3 扫描t_user_info表中的数据

在图3中,控制台把t_user_info表中所有的数据都遍历输出。

7. 删除指定列的数据

在HBaseTest.Java文件中,定义一个testDel()方法用于演示删除t_user_info表中行键为user001的数据。具体代码如下:

 1  @Test
 2  pubic void testDel() throws Exception {
 3    //获取table对象
 4    Table table = conn.getTable(TableName.valueOf("t_user_info"));
 5    //获取delete对象,需要一个rowkey
 6    Delete delete = new Delete("user001".getBytes());
 7    //在delete对象中指定要删除的列族-列名称
 8    delete.addColumn("base_info".getBytes(), "password".getBytes());
 9    //执行删除操作
 10   table.delete(delete);
 11   //关闭
 12   table.close();
 13   conn.close();
 14 }

上述代码中,第4行代码创建一个表对象table,并指定要查看的数据表t_user_info;第6-8行代码创建一个删除对象delete,并指定要删除行键为user001、列族为base_info、列名为password的这一条数据;第10行代码通过表对象table调用delete()方法执行删除操作;第12-13代码关闭表对象和连接对象,避免资源浪费。

运行testDel()方法进行测试,然后在HBase Shell交互式页面执行“scan”命令,查看数据表t_user_info中的数据,具体代码如下:

hbase(main):024:0> scan 't_user_info'
ROW    COLUMN+CELL
user001  column=base_info:username,timestamp=1548486421815,value=zhangsan 
user002  column=base_info:username, timestamp=1548486421815, value=lisi
user002  column=extra_info:married,timestamp=1548486421815,value=false     
2 row(s) in 0.0350 seconds

在上述代码中,发现行键为“user001”、列族为“base_info”且列名为“password”的一列数据没有显示出来,说明这一列数据已经被删除。

8. 删除表

在HBaseTest.Java文件中,定义一个testDrop()方法用于演示删除t_user_info表。具体代码如下:

 1  @Test  
 2  public void testDrop() throws Exception {
 3    //获取一个表的管理器
 4    Admin admin = conn.getAdmin();
 5    //删除表时先需要disable,将表置为不可用,然后在delete
 6    admin.disableTable(TableName.valueOf("t_user_info"));
 7    admin.deleteTable(TableName.valueOf("t_user_info"));
 8    //关闭
 9    admin.close();
 10   conn.close();
 11 }

在上述代码中,第4行代码创建一个表对象table;第6行代码通过表对象table调用disable()方法将表t_user_info设置为不可用状态;第7行代码通过表对象table调用deleteTable()方法执行删除表操作;第12-13代码关闭表对象和连接对象,避免资源浪费。

运行testDel()方法进行测试,然后进入HBase Shell的交互式界面,执行“list”命令查看HBase分布式数据库中的表,具体代码如下:

hbase(main):024:0> list
TABLE
0 row(s) in 0.1430 seconds
=> []

在上述代码中,输出的结果为[ ],表示数据库为空的,说明t_user_info表已经被成功删除。

点击此处
隐藏目录