本文最后更新于:2022-04-19T15:14:44+08:00
使用Maven构建Java项目,需要引入hbase-client
的依赖。
连接构建
要完成对应的操作,首先需要建立本地Java程序与集群的连接,而构建连接需要对应的配置文件。
在分布式环境下,客户端访问HBase需要通过ZooKeeper的地址和端口来获取当前活跃的Master和所需的RegionServer地址。配置文件中至少要指定上面的内容。
首先将配置文件放在项目中的resources
文件夹中,需要的配置文件有HBase的hbase-site.xml
和Hadoop的core-site.xml
。可以使用HBaseConfiguration
的单例方法获取配置。这个方法会去读取我们刚才resource文件夹中的配置文件。如果文件夹中没有放置对应的配置文件也没有关系,可以获取之后使用set方法进行设置(就像下面的情况)。获取配置之后,创建连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private Configuration configuration; private Connection connection;
@Before public void init() throws IOException { configuration = HBaseConfiguration.create(); configuration.set("hbase.zookeeper.quorum", "hadoop102, hadoop103, hadoop104"); configuration.set("hbase.zookeeper.property.clientPort", "2181"); connection = ConnectionFactory.createConnection(configuration); }
@After public void close() throws IOException { connection.close(); }
|
在Java中对于HBase的操作可以分成两大类:对数据表的管理操作和对表中数据的增删改查操作。前者的操作需要获取到Admin
对象,后者的操作需要获取到Table
对象
数据表管理操作
对于数据表的管理等操作需要先得到Admin
对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| private Configuration configuration; private Connection connection; private Admin admin;
@Before public void init() throws IOException { configuration = HBaseConfiguration.create(); configuration.set("hbase.zookeeper.quorum", "hadoop102, hadoop103, hadoop104"); configuration.set("hbase.zookeeper.property.clientPort", "2181"); connection = ConnectionFactory.createConnection(configuration); admin = connection.getAdmin(); }
@After public void close() throws IOException { admin.close(); connection.close(); }
|
创建表
- 调用tableExists判断表是否存在
- 创建表需要构建表描述器(TableDescriptor)、列族描述器(ColumnFamilyDescriptor)。这两个对象需要通过对应的描述器构建器使用build来创建
- 将列族描述器添加到表描述器中
- 使用admin.createTable创建表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public void createTable() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE");
if (admin.tableExists(tableName)) { System.out.println("表已经存在!"); return; }
TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName);
ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("C1"));
ColumnFamilyDescriptor columnFamilyDescriptor = columnFamilyDescriptorBuilder.build(); tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); TableDescriptor tableDescriptor = tableDescriptorBuilder.build();
admin.createTable(tableDescriptor); }
|
由于在HBase中存储的都是byte [
],所以会经常使用到一个工具类Bytes(hbase包下的Bytes工具类),可以使用这个工具类将字符串、long、double等类型转化成byte
[ ]数组,也可以将byte [ ]数组转化成指定类型
删除表
直接调用API即可,注意也是需要先禁用,再删除
1 2 3 4 5 6 7 8 9 10 11
| public void deleteTable() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE"); if (admin.tableExists(tableName)) { admin.disableTable(tableName); admin.deleteTable(tableName); System.out.println("表" + tableName.toString() + "已经删除"); } else { System.out.println("表" + tableName.toString() + "不存在"); } }
|
增删改查操作
对于表的增删改查需要先得到Table对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private Configuration configuration; private Connection connection;
@Before public void init() throws IOException { configuration = HBaseConfiguration.create(); configuration.set("hbase.zookeeper.quorum", "hadoop102, hadoop103, hadoop104"); configuration.set("hbase.zookeeper.property.clientPort", "2181"); connection = ConnectionFactory.createConnection(configuration); }
@After public void close() throws IOException { connection.close(); }
|
HBase的connection对象是一个重量级的对象,编写代码的时候需要避免重复创建,并且它是线程安全的。
而Table对象施一公轻量级的,使用完之后需要close,它是非线程安全的。
插入数据
- 使用HBase连接获取Table对象
- 构建RowKey,列族名和列名
- 构建put对象
- 添加对应列
- 使用Table对象执行put操作
- 关闭Table对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public void put() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE"); Table table = connection.getTable(tableName);
String rowKey = "00001"; String cfName = "C1"; String colName1 = "Name"; String colName2 = "Age";
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(Bytes.toBytes(cfName), Bytes.toBytes(colName1), Bytes.toBytes("syh")); put.addColumn(Bytes.toBytes(cfName), Bytes.toBytes(colName2), Bytes.toBytes("21"));
table.put(put);
table.close(); }
|
通过rowkey获取数据
- 获取Table对象
- 使用rowKey构建get对象
- 执行get请求,得到Result对象(表示逻辑一行)
- 获取所有单元格
- 打印rowkey
- 迭代打印单元格列表
- 关闭表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public void get() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE"); Table table = connection.getTable(tableName);
String rowKey = "00001"; Get get = new Get(Bytes.toBytes(rowKey));
Result result = table.get(get);
List<Cell> cells = result.listCells();
byte[] row = result.getRow(); System.out.println(Bytes.toString(row));
for (Cell cell : cells) { String colFamily = Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); String colName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); String value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
System.out.println(colFamily + ":" + colName + "->" + value); }
table.close(); }
|
注意在循环内部,获取到的都是Array,需要使用offset和length来指定范围
获取所有数据
- 获取Table对象
- 构建scan请求对象
- 执行scan扫描请求,得到ResultScanner对象
- 循环ResultScanner对象,每次得到一个Result对象
- 对每个Result对象,即对每个逻辑行进行输出
- 手动关闭ResultScanner
- 关闭表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public void scan() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE"); Table table = connection.getTable(tableName);
Scan scan = new Scan();
ResultScanner resultScanner = table.getScanner(scan);
for (Result result : resultScanner) { List<Cell> cells = result.listCells(); byte[] row = result.getRow(); System.out.println(Bytes.toString(row));
for (Cell cell : cells) { String colFamily = Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); String colName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); String value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
System.out.println(colFamily + ":" + colName + "->" + value); } }
resultScanner.close();
table.close(); }
|
删除数据
- 获取Table对象
- 根据rowKey构建delete对象
- 执行delete请求
- 关闭表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public void delete() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE"); Table table = connection.getTable(tableName);
String rowKey = "00001"; Delete delete = new Delete(Bytes.toBytes(rowKey));
table.delete(delete);
table.close(); }
|
过滤器使用
过滤器的使用可以结合scan,在构建scan对象之后,利用setFilter进行设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public void scanWithFilter() throws IOException { TableName tableName = TableName.valueOf("MY_TABLE"); Table table = connection.getTable(tableName);
Scan scan = new Scan();
SingleColumnValueFilter startFilter = new SingleColumnValueFilter( Bytes.toBytes("C1"), Bytes.toBytes("Age"), CompareOperator.GREATER_OR_EQUAL, Bytes.toBytes("19")); SingleColumnValueFilter endFilter = new SingleColumnValueFilter( Bytes.toBytes("C1"), Bytes.toBytes("Age"), CompareOperator.LESS_OR_EQUAL, Bytes.toBytes("22")); FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL, startFilter, endFilter); scan.setFilter(filterList);
ResultScanner resultScanner = table.getScanner(scan);
for (Result result : resultScanner) { List<Cell> cells = result.listCells(); byte[] row = result.getRow(); System.out.println(Bytes.toString(row));
for (Cell cell : cells) { String colFamily = Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); String colName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); String value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
System.out.println(colFamily + ":" + colName + "->" + value); } }
resultScanner.close(); table.close(); }
|
可能出现的错误
出现报错:java.lang.NoSuchMethodError: org.apache.hadoop.security.HadoopKerberosName.setRuleMechanism(Ljava/lang/String;)V
缺少依赖:hadoop-auth
没有在本地机器的hosts中配置hadoop102、hadoop103和hadoop104的地址映射