最近工作比较繁忙,在处理需求、写代码的过程中踩到了一些坑,不过问题都被我一个一个解决了,所以最近三周都没有更新博客内容。不过,我是整理了提纲、打了草稿,近期会陆续整理出来。今天就先整理出来一个简单的知识点:使用 Java API 从 HBase 中获取多版本【Version 的概念】数据的方法,开发环境基于 JDK v1.8、HBase v1.1.2、Zookeeper v3.4.6,在演示过程中还会使用原生的 HBase Shell 进行配合,加深理解。
入门概念
先列举一些关于 HBase 的基础概念,有助于继续阅读下文,如果不太了解需要先回顾一下:
- 列式分布式数据库,基于
Google BigTable论文开发,适合海量的数据存储 - Rowkey、Column Family、Qualifier、Timestamp、Cell、Version 的概念
- HBase Shell、Java API、Phoenix
示例代码
下面的演示会以 HBase Shell、Java API 这两种方式分别进行,便于读者理解。
建表造数据
为了使用 Java API 获取多版本数据,我要先做一些基础工作:创建表、造数据、造多版本数据。为了尽量简化数据的复杂度,以及能让读者理解,我准备了 2 条数据,下面使用一个表格来整理这 2 条数据,读者可以看得更清晰:
| Rowkey | Column Family | Qualifier | Version | Value |
|---|---|---|---|---|
| row01 | cf | name | 1 | JIM |
| row01 | cf | name | 2 | Jack |
| row02 | cf | name | 1 | Lucy |
| row02 | cf | age | 1 | 20 |
从上表可以看出,一共 2 条数据,row01 有 1 列,2 个版本,row02 有 2 列,1 个版本。下面使用原生的 HBase Shell 开始逐步建表、造数据。
1、进入交互式客户端
使用 hbase shell 进入交互式客户端,在输出的日志中可以看到当前环境 HBase 的版本号。
登录成功后终端显示:

2、创建表:学生表
使用 create 'TB_HBASE_STUDENT','cf' 创建一张表,为了便于后面的操作,表名最好使用大写形式,否则涉及到表名的操作需要加单引号。由于 HBase 是列式存储结构,所以创建表时不需要指定具体的列名称,只要指定 Column Family 名称即可。
执行后终端显示:
1 | 0 row (s) in 2.5260 seconds |

3、查看表结构
使用 describe 'TB_HBASE_STUDENT' 查看表结构,执行后终端显示:
1 | Table TB_HBASE_STUDENT is ENABLED |

可以看到表的基本信息,其中 Column Family 名称为 cf,最大版本 VERSIONS 为 1,这会导致只会存储一个版本的列数据,当再次插入数据的时候,后面的值会覆盖掉前面的值。
4、修改最大版本
为了满足我的需求,需要更改表,把 cf 的最大版本数 VERSIONS 增加,设置为 3 。使用 alter 'TB_HBASE_STUDENT',{NAME=>'cf',VERSIONS=>3} 命令即可。执行后终端显示:
1 | Updating all regions with the new schema... |

修改成功后,我使用 describe 'TB_HBASE_STUDENT' 再次查看表结构,终端显示:
1 | Table TB_HBASE_STUDENT is ENABLED |

这次可以看到,VERSIONS => '3' 表示 cf 已经支持存储 3 个版本的数据了。
5、插入 2 条数据
HBase 的插入数据功能是使用 put 命令,每次插入 1 列,根据上述表格数据格式,需要执行 4 次 put 操作。
1 | put 'TB_HBASE_STUDENT','row01','cf:name','JIM' |
执行后终端显示如下:
1 | 1.8.7-p357 :012 > put 'TB_HBASE_STUDENT','row01','cf:name','JIM' |

命令行查看
1、先尝试使用 get 命令来获取这 2 条数据,分别执行 3 次 get 操作。
1 | get 'TB_HBASE_STUDENT','row02','cf:name' |
执行后终端显示如下:
1 | 1.8.7-p357 :026 > get 'TB_HBASE_STUDENT','row02','cf:name' |

可以看到,此时并没有获取到 row01 的 2 个版本的数据,只获取了最新版本的结果。
2、使用 get 获取多版本数据,执行 get 时需要加上 VERSIONS 相关的参数。
1 | get 'TB_HBASE_STUDENT','row01',{COLUMN=>'cf:name',VERSIONS=>3} |
执行后终端显示如下:
1 | 1.8.7-p357 :029 > get 'TB_HBASE_STUDENT','row01',{COLUMN=>'cf:name',VERSIONS=>3} |

可以看到,2 个版本的数据都读取出来了。
3、使用 scan 扫描数据
此外还有一个 scan 命令可以扫描表中的数据,使用 scan 'TB_HBASE_STUDENT',{LIMIT=>5} 尝试扫描 5 条数据出来。
执行后终端显示如下:
1 | 1.8.7-p357 :031 > scan 'TB_HBASE_STUDENT',{LIMIT=>5} |

由于表中只有 2 条数据,所以只显示出 2 条,而且 scan 默认也是获取最新版本的数据结果。
4、如果想退出 HBase Shell 交互式客户端,使用 !quit 命令即可。

代码示例
上面使用原生的 HBase Shell 操作演示了创建表、插入数据、读取数据的过程,下面将使用 Java API 演示读取数据的过程,而创建表、插入数据的过程就不再演示。
这里需要特别注意,为了正常使用 Java API 的相关接口,Java 项目需要依赖 hbase-client、commons-configuration、hadoop-auth、hadoop-hdfs 等组件。我的代码已经上传至 GitHub,详见:TestHBase.java ,搜索类名 TestHBase 即可。
1、代码示例
代码结构比较简单,分为:构造查询请求、发送请求、解析结果输出几部分,注释中也注明了各个部分的作用,总计也就 50 行代码左右。
1 | /** |
2、运行结果
执行运行,可以看到结果输出,与数据表中一致,多版本数据结果也可以全部获取:
1 | 2019-08-18_17:54:18 [main] INFO test.TestHBase:58: ====get result by first method |

备注
1、在使用 Java API 时注意低版本、高版本之间的差异,必要时及时升级,就像上文代码中的 Result.getColumn、KeyValue.getValue ()、Cell.getValue () 这几个方法。
2、Phoenix 是一款基于 HBase 的工具,在 HBase 之上提供了 OLTP 相关的功能,例如完全的 ACID 支持、SQL、二级索引等,此外 Phoenix 还提供了标准的 JDBC 的 API。在使用 Phoenix 时,可以很方便地像操作 SQL 那样操作 HBase。
使用 Phoenix 创建表、查询数据示例如图。
创建表,使用:CREATE TABLE IF NOT EXISTS TB_HBASE_STUDENT ("pk"varchar primary key,"cf"."name"varchar,"cf"."age"varchar);

查询示例,使用:select * from"TB_HBASE_STUDENT"limit 5;

3、本示例的代码放在 GirHub,详见:TestHBase.java ,搜索类名 TestHBase 即可。参考 GitHub 的代码时,注意在 iplaypistudy-common-config 模块中增加自己的配置文件,如果开发环境的版本不匹配,也要升级版本,在 pom.xml 更改即可。
4、想要使用 HBase Shell 删除表时,必须先使用 disable YOUR_TABLE_NAME 来禁用表,然后再使用 drop YOUR_TABLE_NAME 删除表,直接删除表是不被允许的。

