HBase 是一个分布式的、面向列的开源的 NoSQL 数据库。Spring Boot 项目如果需要操作 HBase 通常有如下几种客户端可以使用:

  • hbase-client:比较底层,需要自己进一步封装 api,而且版本号和安装的 hbase 也要匹配,否则会报错
  • spring-data-hadoop:2019 年 4 月 5 停止维护
  • Apache Phoenix:使用 SQL 的方式来操作 HBase。Phoenix 的性能很高(进行简单查询,其性能量级是毫秒),相对于 hbase 原生的 scan 并不会差多少,而对于类似的组件 hive、Impala 等,性能有着显著的提升

    本文演示如何使用 hbase-client 操作 HBase 数据库。

一、安装配置

1,环境准备

(1)HBase 的安装

(2)同时 HBase 服务器主机名不能为 localhost或者VM-16-6-centos,否则客户端无法连接

2,项目配置

(1)首先编辑项目的 pom.xml 文件,添加 hbase-client

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>2.3.0</version>
</dependency>

(2)然后在 application.properties 中添加 HBase 相关配置(即 ZooKeeper 的地址和端口):

# HBase 数据源配置
hbase.config.hbase.zookeeper.quorum=86.168.xx.xx
hbase.config.hbase.zookeeper.property.clientPort=2181

yml版本

hbase:
  config:
    hbase:
      zookeeper:
        property:
          clientPort: 2181
        quorum: 81.68.xx.xx

3,编写工具类

(1)首先编写 HBaseConfig.java 来读取配置文件,获取 hbase

@Configuration
@ConfigurationProperties(prefix = "hbase")
public class HBaseConfig {
 
    private Map<String, String> config = new HashMap<>();
 
    public Map<String, String> getConfig() {
        return config;
    }
 
    public void setConfig(Map<String, String> config) {
        this.config = config;
    }
 
    public org.apache.hadoop.conf.Configuration configuration() {
        org.apache.hadoop.conf.Configuration configuration = HBaseConfiguration.create();
//此处可自己自定义和改造 拓展用
       //        configuration.set(HBASE_QUORUM, "81.68.xx.xx:2181");
//        configuration.set(HBASE_ROOTDIR, "/");
//        configuration.set(HBASE_ZNODE_PARENT, "/hbase");
        for(Map.Entry<String, String> map : config.entrySet()){
            configuration.set(map.getKey(), map.getValue());
        }
        return configuration;
    }
 
    @Bean
    public Admin admin() {
        Admin admin = null;
        try {
            Connection connection = ConnectionFactory.createConnection(configuration());
            admin = connection.getAdmin();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return admin;
    }
}

(2)由于 hbase-client 比较底层,我们还要封装一个 HBaseUtils.java 工具类,实现创建表、插入、读取、删除数据:

@Service
public class HBaseUtils {

    @Autowired
    private Admin hbaseAdmin;

    /**
     * 判断表是否存在
     *
     * @param tableName 表名
     * @return true/false
     */
    public boolean isExists(String tableName) {
        boolean tableExists = false;
        try {
            TableName table = TableName.valueOf(tableName);
            tableExists = hbaseAdmin.tableExists(table);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tableExists;
    }

    /**
     * 创建表
     * @param tableName 表名
     * @param columnFamily 列族
     * @return true/false
     */
    public boolean createTable(String tableName, List<String> columnFamily) {
        return createTable(tableName, columnFamily, null);
    }

    /**
     * 预分区创建表
     * @param tableName 表名
     * @param columnFamily 列族
     * @param keys 分区集合
     * @return true/false
     */
    public boolean createTable(String tableName, List<String> columnFamily, List<String> keys) {
        if (!isExists(tableName)) {
            try {
                TableName table = TableName.valueOf(tableName);
                HTableDescriptor desc = new HTableDescriptor(table);
                for (String cf : columnFamily) {
                    desc.addFamily(new HColumnDescriptor(cf));
                }
                if (keys == null) {
                    hbaseAdmin.createTable(desc);
                } else {
                    byte[][] splitKeys = getSplitKeys(keys);
                    hbaseAdmin.createTable(desc, splitKeys);
                }
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(tableName + "is exists!!!");
            return false;
        }
        return false;
    }

    /**
     * 删除表
     *
     * @param tableName 表名
     */
    public void dropTable(String tableName) throws IOException {
        if (isExists(tableName)) {
            TableName table = TableName.valueOf(tableName);
            hbaseAdmin.disableTable(table);
            hbaseAdmin.deleteTable(table);
        }
    }

    /**
     * 插入数据(单条)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param column 列
     * @param value 值
     * @return true/false
     */
    public boolean putData(String tableName, String rowKey, String columnFamily, String column,
                           String value) {
        return putData(tableName, rowKey, columnFamily, Arrays.asList(column),
                Arrays.asList(value));
    }

    /**
     * 插入数据(批量)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param columns 列
     * @param values 值
     * @return true/false
     */
    public boolean putData(String tableName, String rowKey, String columnFamily,
                           List<String> columns, List<String> values) {
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Put put = new Put(Bytes.toBytes(rowKey));
            for (int i=0; i<columns.size(); i++) {
                put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columns.get(i)),
                        Bytes.toBytes(values.get(i)));
            }
            table.put(put);
            table.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取数据(全表数据)
     * @param tableName 表名
     * @return map
     */
    public List<Map<String, String>> getData(String tableName) {
        List<Map<String, String>> list = new ArrayList<>();
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Scan scan = new Scan();
            ResultScanner resultScanner = table.getScanner(scan);
            for(Result result : resultScanner) {
                HashMap<String, String> map = new HashMap<>();
                //rowkey
                String row = Bytes.toString(result.getRow());
                map.put("row", row);
                for (Cell cell : result.listCells()) {
                    //列族
                    String family = Bytes.toString(cell.getFamilyArray(),
                            cell.getFamilyOffset(), cell.getFamilyLength());
                    //列
                    String qualifier = Bytes.toString(cell.getQualifierArray(),
                            cell.getQualifierOffset(), cell.getQualifierLength());
                    //值
                    String data = Bytes.toString(cell.getValueArray(),
                            cell.getValueOffset(), cell.getValueLength());
                    map.put(family + ":" + qualifier, data);
                }
                list.add(map);
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取数据(根据传入的filter)
     * @param tableName 表名
     * @param filter 过滤器
     * @return map
     */
    public List<Map<String, String>> getData(String tableName, Filter filter) {
        List<Map<String, String>> list = new ArrayList<>();
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Scan scan = new Scan();
            // 添加过滤器
            scan.setFilter(filter);
            ResultScanner resultScanner = table.getScanner(scan);
            for(Result result : resultScanner) {
                HashMap<String, String> map = new HashMap<>();
                //rowkey
                String row = Bytes.toString(result.getRow());
                map.put("row", row);
                for (Cell cell : result.listCells()) {
                    //列族
                    String family = Bytes.toString(cell.getFamilyArray(),
                        cell.getFamilyOffset(), cell.getFamilyLength());
                    //列
                    String qualifier = Bytes.toString(cell.getQualifierArray(),
                        cell.getQualifierOffset(), cell.getQualifierLength());
                    //值
                    String data = Bytes.toString(cell.getValueArray(),
                        cell.getValueOffset(), cell.getValueLength());
                    map.put(family + ":" + qualifier, data);
                }
                list.add(map);
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取数据(根据rowkey)
     * @param tableName 表名
     * @param rowKey rowKey
     * @return map
     */
    public Map<String, String> getData(String tableName, String rowKey) {
        HashMap<String, String> map = new HashMap<>();
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Get get = new Get(Bytes.toBytes(rowKey));
            Result result = table.get(get);
            if (result != null && !result.isEmpty()) {
                for (Cell cell : result.listCells()) {
                    //列族
                    String family = Bytes.toString(cell.getFamilyArray(),
                            cell.getFamilyOffset(), cell.getFamilyLength());
                    //列
                    String qualifier = Bytes.toString(cell.getQualifierArray(),
                            cell.getQualifierOffset(), cell.getQualifierLength());
                    //值
                    String data = Bytes.toString(cell.getValueArray(),
                            cell.getValueOffset(), cell.getValueLength());
                    map.put(family + ":" + qualifier, data);
                }
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 获取数据(根据rowkey,列族,列)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param columnQualifier 列
     * @return map
     */
    public String getData(String tableName, String rowKey, String columnFamily,
                          String columnQualifier) {
        String data = "";
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Get get = new Get(Bytes.toBytes(rowKey));
            get.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columnQualifier));
            Result result = table.get(get);
            if (result != null && !result.isEmpty()) {
                Cell cell = result.listCells().get(0);
                data = Bytes.toString(cell.getValueArray(), cell.getValueOffset(),
                        cell.getValueLength());
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 删除数据(根据rowkey)
     * @param tableName 表名
     * @param rowKey rowKey
     */
    public void deleteData(String tableName, String rowKey) throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        table.delete(delete);
        table.close();
    }

    /**
     * 删除数据(根据rowkey,列族)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     */
    public void deleteData(String tableName, String rowKey, String columnFamily)
            throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        delete.addFamily(columnFamily.getBytes());
        table.delete(delete);
        table.close();
    }

    /**
     * 删除数据(根据rowkey,列族)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param column 列
     */
    public void deleteData(String tableName, String rowKey, String columnFamily, String column)
            throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        delete.addColumn(columnFamily.getBytes(), column.getBytes());
        table.delete(delete);
        table.close();
    }

    /**
     * 删除数据(多行)
     * @param tableName 表名
     * @param rowKeys rowKey集合
     */
    public void deleteData(String tableName, List<String> rowKeys) throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        List<Delete> deleteList = new ArrayList<>();
        for(String row : rowKeys){
            Delete delete = new Delete(Bytes.toBytes(row));
            deleteList.add(delete);
        }
        table.delete(deleteList);
        table.close();
    }

    /**
     * 分区【10, 20, 30】 -> ( ,10] (10,20] (20,30] (30, )
     * @param keys 分区集合[10, 20, 30]
     * @return byte二维数组
     */
    private byte[][] getSplitKeys(List<String> keys) {
        byte[][] splitKeys = new byte[keys.size()][];
        TreeSet<byte[]> rows = new TreeSet<>(Bytes.BYTES_COMPARATOR);
        for(String key : keys) {
            rows.add(Bytes.toBytes(key));
        }
        int i = 0;
        for (byte[] row : rows) {
            splitKeys[i] = row;
            i ++;
        }
        return splitKeys;
    }
}

 

附:使用样例

(1)下面创建一个 Controller 调用 HBaseUtils 来操作 HBase 数据库:

@RestController
@AllArgsConstructor
@RequestMapping("/common/front")
public class FrontController {
 
    @Autowired
    private HBaseUtils hbaseUtils;
 
    @GetMapping("/test")
    public void test() throws IOException {
        System.out.println("---开始创建test表---");
        hbaseUtils.createTable("test", Arrays.asList("cf"));
 
        System.out.println("---判断test表是否存在---");
        Boolean t = hbaseUtils.isExists("test");
        System.out.println(t);
 
        System.out.println("\n---插入一列数据---");
        hbaseUtils.putData("test", "row1", "cf", "a", "value1-1");
 
        System.out.println("\n---插入多列数据---");
        hbaseUtils.putData("test", "row2", "cf",
                Arrays.asList("a", "b", "c"),  Arrays.asList("value2-1", "value2-2", "value2-3"));
 
        System.out.println("\n---根据rowkey、列族、列查询数据---");
        String columnData = hbaseUtils.getData("test", "row2", "cf", "b");
        System.out.println(columnData);
 
        System.out.println("\n---根据rowkey查询数据---");
        Map<String, String> rowData = hbaseUtils.getData("test", "row2");
        System.out.println(rowData);
 
        System.out.println("\n---查询全表数据---");
        List<Map<String, String>> tableData = hbaseUtils.getData("test");
        System.out.println(tableData);
 
        System.out.println("\n---根据rowkey、列族、列删除数据---");
        hbaseUtils.deleteData("test", "row2", "cf", "b");
 
        System.out.println("\n---根据rowkey、列族删除数据---");
        hbaseUtils.deleteData("test", "row2", "cf");
 
        System.out.println("\n---根据rowkey删除数据---");
        hbaseUtils.deleteData("test", "row2");
 
        System.out.println("\n---根据rowkey批量删除数据---");
        hbaseUtils.deleteData("test", Arrays.asList("row1", "row2"));
 
        System.out.println("\n---删除表---");
        hbaseUtils.dropTable("test");
    }
}

2)使用浏览器访问 /test 接口,可以看到控制台输出如下:

springboot hbase整合 springboot连接hbase集群_springboot hbase整合