HBase API

news2024/11/24 13:36:53

我们之后的实际开发中不可能在服务器那边直接使用shell命令一直敲的,一般都是通过API进行操作的。

环境准备

新建Maven项目,导入Maven依赖

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

1、创建连接

        HBase 的客户端连接由 ConnectionFactory 类来创建(工厂模式直接创建),我们使用完之后需要手动关闭连接。同时连接 是一个重量级的,推荐一个进程使用一个连接,对 HBase 的命令通过连接中的两个属性 Admin 和 Table 来实现。其中 Admin 主要是针对元数据-表格的创建修改进行操作, Table 则是针对表格中数据的增加修改进行操作。

1.1、单线程创建连接

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.AsyncConnection;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;

public class HBaseConnection {
    public static void main(String[] args) throws IOException {

        // 1. 创建连接配置参数
        Configuration conf = new Configuration();
        //对应我们 hbase-site.xml 中的配置信息的<name>和<value>的值
        conf.set("hbase.zookeeper.quorum","hadoop102,hadoop103,hadoop104");

        // 2. 创建连接
        // 默认使用同步连接
        Connection connection = ConnectionFactory.createConnection(conf);

        // 3. 使用连接
        System.out.println(connection);

        // 4. 关闭连接
        connection.close();
    }
}

1.2、多线程创建连接

我们真正开发中首先不会把配置参数写到代码中的,我们是通过Maven项目下的resources目录来读取配置文件来设置配置参数的,我们可以看源码:

Connection connection = ConnectionFactory.createConnection();

我们调用了工厂模式的 ConnectionFactory 的 createConnection 方法来创建连接,这里我们。

没有配置参数,因为HBase默认其实会自动帮我们添加配置参数:

我们可以看到当调用ConnectionFactory 的 createConnection 方法的时候,其实又调用了HBaseConfiguration 的 create 方法,

 

 该方法内部帮我们添加了配置参数:

可以看到,它其实是去读取我们Maven项目下的resources目录下的文件,所以我们需要将我们的配置参数写到resources目录下,最好使用 "hbase-ste.xml" 来命名,至于这个文件,我们直接复制我们hbase集群中conf目录下的hbase-site.xml 。 

其中,我们只需要留下关于我们zookeeper服务器连接地址的配置信息即可,别的全部删除,因为我们是客户端,我们不能设置服务端的配置,那些即使写了也不会生效。

 

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop102,hadoop103,hadoop104</value>
        <description>The directory shared by RegionServers.</description>
    </property>
</configuration>

 使用类单例模式确保只使用一个连接,可以同时用于多个线程。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.AsyncConnection;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;

public class HBaseConnection {

    // 声明一个静态属性
    public static Connection connection = null;

    static {
        // 1. 创建连接
        // 默认使用同步连接
        try {
            //使用读取本地配置文件的方式来添加参数
            connection = ConnectionFactory.createConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void closeConnection() throws IOException {
        // 判断连接是否为 null
        if (connection != null){
            connection.close();
        }
    }

    public static void main(String[] args) throws IOException {

        //使用多线程连接 直接使用创建好的连接 不再main线程单独创建
        System.out.println(HBaseConnection.connection);

        //在main线程的最后记得关闭连接
        HBaseConnection.closeConnection();
    }

}

2、DDL

创建 HBaseDDL类,添加HBaseConnection的静态属性作为我们的连接对象,确保单例模式。

2.1、创建命名空间

我们上面说了,HBase中的 DDL 语句被封装到了 Admin中,所以我们需要先获取 Admin。

Admin admin = connection.getAdmin();

注意:在coding的过程中遇到异常不要老想着直接在方法名之后直接 throws ,这样虽然是简洁了一些,但是如果第一行抛出了一个IOException,之后几行再出现异常我们就察觉不到了,所以尽量在我们核心代码处try-catch,方便了解异常信息。

然后我们直接通过方法来创建 namespace ,这里的namespace是一个对象,这样做的原因是因为我们 HBase 的shell命令中创建namespace的时候就是不止一种方法,所以这里单纯字符串来创建namespace肯定不行,对象具有更完整属性。

第二种创建命名空间的方式中,我们可以看到有一个 键值对参数,这就需要设置我们对象的属性了。 

 

import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;

import java.io.IOException;

public class HBaseDDL {

    public static Connection connection = HBaseConnection.connection;

    /**
     * 创建命名空间
     * @param namespace 命名空间的名称
     */
    public static void createNamespace(String namespace) throws IOException {

        // 1. 获取admin
        //admin是轻量级的 并且不是线程安全的 不推荐池化或者缓存这个连接
        //也就是说 用的时候再去获取 不用就把它关闭掉
        Admin admin = connection.getAdmin();

        // 2. 调用方法创建 namespace
        // 代码比shell更加底层 所以shell能实现的功能代码 一定也可以
        // 所以代码实现时 需要更完整的命名空间描述

        // 2.1 获取一个命名空间的建造者 => 设计师
        NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);

        // 2.2 给命名空间添加属性
        // 给namespace添加键值对属性其实并没有什么意义 只是给人注释一样
        builder.addConfiguration("user","lyh");

        // 2.3 使用builder构造出namespace对象
        // 创建命名空间造成的问题 属于方法本身的问题 不应该抛出
        try {
            admin.createNamespace(builder.build());
        } catch (IOException e) {
            System.out.println("该命名空间已经存在!");
            e.printStackTrace();
        }

        // 3. 关闭资源
        admin.close();

    }
    public static void main(String[] args) throws IOException {
        //测试创建马命名空间
        createNamespace("lyh");

        //记得关闭HBase连接
        HBaseConnection.closeConnection();
    }
}

运行结果 

 

2.2、判断表格是否存在

    /**
     * 判断表格是否存在
     * @param namespace 命名空间
     * @param tableName 表名
     * @return true-存在 false-不存在
     */
    public static boolean isTableExists(String namespace,String tableName) throws IOException {
        // 1. 获取admin
        Admin admin = connection.getAdmin();

        // 2. 使用方法判断表格是否存在
        boolean b = false;
        try {
            b = admin.tableExists(TableName.valueOf(namespace, tableName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // 3. 关闭admin
        admin.close();
        
        // 4.返回结果
        return b;
    }

2.3、创建表

    /**
     * 创建表格
     * @param namespace 命名空间
     * @param tableName 表格名称
     * @param columnFamilies 列族名称 可以有多个
     */
    public static void createTable(String namespace,String tableName,String... columnFamilies) throws IOException {
        
        // 判断是否有至少一个列族
        if (columnFamilies.length == 0){
            System.out.println("创建表格至少应该有一个列族");
            return;
        }

        // 判断表格是否已经存在
        if (isTableExists(namespace,tableName)){
            System.out.println("表格已经存在");
            return;
        }


        // 1. 获取admin
        Admin admin = connection.getAdmin();

        // 2. 调用方法创建表格
        // 2.1 获取表格的建造者
        TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(namespace,tableName));

        // 2.2 添加参数
        for (String columnFamily : columnFamilies) {
            // 2.3 获取列族建造者
            ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily));

            // 2.4 通过建造者创建对应列族描述
            // 添加版本参数-维护的版本数
            columnFamilyDescriptorBuilder.setMaxVersions(5);

            // 2.5 创建添加完参数的列族描述
            builder.setColumnFamily(columnFamilyDescriptorBuilder.build());
        }
        // 2.3 创建表格描述
        try {
            admin.createTable(builder.build());
        } catch (IOException e) {
            //System.out.println("表格已经存在");
            e.printStackTrace();
        }

        // 2.4 关闭admin
        admin.close();
    }

2.4、修改表

这里需要注意的比较多:

我们这里修改表格的列族版本,首先就需要获取表格描述和列族描述,但是我们不能重新通过newBuilder创建这两种描述,而是应该使用旧的描述。

对于旧的表格描述来说,我们可以通过admin的getDescriptor()来获取旧的描述。

对于旧的列族描述来说,我们可以通过表格描述对象的getColumnFamily()方法来获取。

    /**
     * 修改表格中一个列族的版本
     * @param namespace 命名空间
     * @param tableName 表名
     * @param columnFamily 列族
     * @param version 维护的版本
     */
    public static void modifyTable(String namespace,String tableName,String columnFamily,int version) throws IOException {

        // 判断表格是否存在
        if (!isTableExists(namespace,tableName)){
            System.out.println("表格不存在");
            return;
        }

        // 1. 获取admin
        Admin admin = connection.getAdmin();

        // 2. 调用方法修改表格
        // 2.0 获取之前的表格描述
        TableDescriptor tableDescriptor = null;
        try {
            tableDescriptor = admin.getDescriptor(TableName.valueOf(namespace, tableName));
        } catch (IOException e) {
            System.out.println("表格不存在");
            e.printStackTrace();
        }

        // 2.1 创建一个表格描述建造者
        // 如果使用填写 tableName 的方法 相当于创建了一个新的表格描述 没有之前的信息
        // 如果想要修改表格的信息 必须调用方法填写一个旧的表格描述
        TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor);

        // 2.2 对应建造者进行表格数据的修改
        // 获取旧的列族描述
        ColumnFamilyDescriptor columnFamily1 = tableDescriptor.getColumnFamily(Bytes.toBytes(columnFamily));

        // 创建列族描述建造者
        ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(columnFamily1);

        // 修改对应的版本
        columnFamilyDescriptorBuilder.setMaxVersions(version);

        // 在这里修改的时候 如果填写的是新创建的列族描述 那么我们表格之前的其它属性会被初始化 所以要使用旧的列族描述
        builder.modifyColumnFamily(columnFamilyDescriptorBuilder.build());

        try {
            admin.modifyTable(builder.build());
        } catch (IOException e) {

            e.printStackTrace();
        }

        // 3. 关闭admin
        admin.close();
    }

 

2.5、删除表

需要注意HBase中删除表前必须标记表为不可用!

/**
     * 删除表格
     * @param namespace 命名空间
     * @param tableName 表名
     * @return true-删除成功
     */
    public static boolean deleteTable(String namespace,String tableName) throws IOException {
        // 1. 判断表格是否存在
        if (!isTableExists(namespace,tableName)){
            System.out.println("表格不存在 无法删除");
            return false;
        }

        // 2. 获取admin
        Admin admin = connection.getAdmin();

        // 3. 调用相关的方法删除表格
        try {
            // hbase 删除表格前必须标记标记表格为不可用才能删除
            admin.disableTable(TableName.valueOf(namespace,tableName));
            admin.deleteTable(TableName.valueOf(namespace,tableName));
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 4. 关闭admin
        admin.close();

        return true;
    }

3、DML

3.1、插入数据

我们可以看到,插入数据的put方法中要求参数必须为Byte类型,这也应证了我们之前第一篇博客说的-HBase的Cell的数据都是以Byte字节类型存储的。

public class HBaseDML {

    //静态属性
    public static Connection connection = HBaseConnection.connection;

    /**
     * 插入数据
     * @param namespace 命名空间
     * @param tableName 表名
     * @param rowKey 行键
     * @param columnFamily 列族
     * @param columnName 列名
     * @param value 值
     */
    public static void putCell(String namespace,String tableName,String rowKey,String columnFamily,String columnName,String value) throws IOException {

        // 1. 获取 Table
        Table table = connection.getTable(TableName.valueOf(namespace,tableName));

        // 2. 调用相关方法实现数据插入
        // 2.1 创建 put 对象
        Put put = new Put(Bytes.toBytes(rowKey));

        // 2.2 给 put 对象添加属性
        put.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName),Bytes.toBytes(value));

        // 2.3 将对象写入对应的方法
        try {
            table.put(put);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 3. 关闭table
        table.close();
    }

    public static void main(String[] args) throws IOException {

        // 测试插入数据
        putCell("bigdata","student","1005","info","name","hbase");

        System.out.println("其他代码");

        // 关闭连接
        HBaseConnection.closeConnection();
    }
}

3.2、查询数据

未完待续

3.3、扫描数据

3.4、带过率扫描

3.5、删除数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/850041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络性能指标

比特&#xff1a;数据量的单位 KB 2^10B 2^13 bit 比特率&#xff1a;连接在计算机网络上的主机在数字通道上传送比特的速率 kb/s 10^3b/s 带宽&#xff1a;信号所包含的各种频率不同的成分所占据的频率范围 Hz 表示在网络中的通信线路所能传送数据的能力&#xff08…

CentOS虚拟机更改屏幕锁屏时间

&#xff08;1&#xff09;点击“应用程序”&#xff0c;再点击“系统工具”&#xff0c;再点击“设置” &#xff08;2&#xff09; &#xff08;3&#xff09;在“设置”中点击“Privacy”&#xff0c;点击“锁屏”

【博客691】VictoriaMetrics如何支持Multi Retention

VictoriaMetrics如何支持Multi Retention 场景&#xff1a; 实现Multi Retention Setup within VictoriaMetrics Cluster&#xff0c;使得为不同的监控数据采用不同的保存时间 Multi Retention实现方式 方式&#xff1a; VictoriaMetrics 的社区版本通过 -retentionPeriod 命…

系统学习Linux-Redis基础

一、redis概述 NoSQL&#xff08;非关系型数据库、内存存储&#xff09; 类型 文档型数据库&#xff08;Document-oriented database&#xff09;如MongoDB&#xff1b; 列族数据库&#xff08;Column-family database&#xff09;如HBase、Cassandra等&#xff1b; 图形数…

如何将视频转成gif图?视频怎么转gif高清图片?

在看电视或是短视频的时候&#xff0c;总能发现一些有趣的片段&#xff0c;当想把这些视频转gif图片发送给朋友的时候该怎么处理呢&#xff1f;其实可以试试专业的视频转gif工具&#xff0c;本文介绍一个视频在线转gif的方法&#xff0c;一起来了解一下吧。 打开首页&#xff…

Profibus DP主站转Modbus TCP网关profibus主站模拟软件

捷米JM-DPM-TCP网关。这款产品在Profibus总线侧实现了主站功能&#xff0c;在以太网侧实现了ModbusTcp服务器功能&#xff0c;为我们的工业自动化网络带来了全新的可能。 捷米JM-DPM-TCP网关是如何实现这些功能的呢&#xff1f;首先&#xff0c;让我们来看看它的Profibus总线侧…

IPC之三:使用 System V 消息队列进行进程间通信的实例

IPC 是 Linux 编程中一个重要的概念&#xff0c;IPC 有多种方式&#xff0c;本文主要介绍消息队列(Message Queues)&#xff0c;消息队列可以完成同一台计算机上的进程之间的通信&#xff0c;相比较管道&#xff0c;消息队列要复杂一些&#xff0c;但使用起来更加灵活和方便&am…

C++的auto究竟是何方神圣

C的auto究竟是何方神圣 前言&#x1f64c;auto&#xff08;C 11&#xff09; 的使用细则auto是什么&#xff1f; auto声明的变量是在什么时期被编译器推导出来呢&#xff1f;为什么使用auto进行定义变量时&#xff0c;必须进行初始化&#xff1f; auto 的使用场景auto与指针和引…

gitee分支合并

合并dev分支到master&#xff08;合并到主分支&#xff09; git checkout master git merge dev //这里的dev表示你的分支名称 git push //推送到远程仓库 效果如下图 不报错就表示推送成功了&#xff0c;希望能帮助各位小伙伴

Flamingo

基于已有的图像模型和文本模型构建多模态模型。输入是图像、视频和文本&#xff0c;输出是文本。 Vision encoder来自预训练的NormalizerFree ResNet (NFNet)&#xff0c;之后经过图文对比损失学习。图片经过图像模型的输出是2D grid&#xff0c;视频按1FPS的频率采样后经过图…

python优雅地爬虫

申明&#xff1a;仅用作学习用途&#xff0c;不提供任何的商业价值。 背景 我需要获得新闻&#xff0c;然后tts&#xff0c;在每天上班的路上可以听一下。具体的方案后期我也会做一次分享。先看我喜欢的万能的老路&#xff1a;获得html内容-> python的工具库解析&#xff0…

Running Homebrew as root is extremely dangerous and no longer supported

Running Homebrew as root is extremely dangerous and no longer supported 查看磁盘所有信息 在使用homebrew安装smartmontools&#xff0c;查看Mac磁盘信息&#xff0c;包括mac磁盘写入量、mac磁盘健康、磁盘启动次数等&#xff0c;遇到的问题及解决方案 使用brew install s…

单片机开发 esp8266

一、固件界面 二、项目介绍 固件名称&#xff1a;esp8266-universalboard v1.0 提供商&#xff1a; 半条虫(466814195) 下载&#xff1a;esp8266-universalboard.bin 源码地址&#xff1a;Gitlab

STM32 F103C8T6学习笔记1:开发环境与原理图的熟悉

作为一名大学生&#xff0c;学习单片机有一段时间了&#xff0c;也接触过嵌入式ARM的开发&#xff0c;但从未使用以及接触过STM32C8T6大开发使用&#xff0c;于是从今日开始&#xff0c;将学习使用它~ 本文介绍STM32C8T6最小系统开发环境搭建注意问题&#xff0c;STM32C8T6单片…

TCP的四次挥手与TCP状态转换

文章目录 四次挥手场景步骤TCP状态转换 四次挥手场景 TCP客户端与服务器断开连接的时候&#xff0c;在程序中使用close()函数&#xff0c;会使用TCP协议四次挥手。 客户端和服务端都可以主动发起。 因TCP连接时候是双向的&#xff0c;所以断开的时候也是双向的。 步骤 三次…

dueling network原理和实现

算法原理&#xff1a; Q ( s , a ; θ , α , β ) V ( s ; θ , β ) ( A ( s , a ; θ , α ) − max ⁡ a ′ ∈ ∣ A ∣ A ( s , a ′ ; θ , α ) ) . \begin{gathered}Q(s,a;\theta,\alpha,\beta)V(s;\theta,\beta)\left(A(s,a;\theta,\alpha)-\max_{a\in|\mathcal{A}…

网络编程(JavaEE初阶系列10)

目录 前言&#xff1a; 1.网络编程的基础 1.1为什么需要网络编程 1.2什么是网络编程 1.3网络编程中的基本概念 1.3.1发送端和接收端 1.3.2请求和响应 1.3.3客户端和服务端 2.Socket套接字 2.1概念 2.2分类 3.UDP数据报套接字编程 3.1DataGramSocket API 3.2Datagr…

【刷题笔记8.8】LeetCode题目:两数之和

LeetCode&#xff08;Hot100&#xff09;&#xff1a;两个数之和 题目描述及示例&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会…

《合成孔径雷达成像算法与实现》Figure3.3

代码复现如下&#xff1a; clc clear all close all%参数设置 TBP [25,50,100,200,400]; %时间带宽积 T 1e-6; %脉冲持续时间H figure; for i 1:5% 参数计算B TBP(i)/T; % 信号带宽K B/T; % 线性调频频率alp…

分布式协议与算法——Paxos算法

目录 Paxos算法Basic Paxos算法三种角色如何达成共识&#xff08;协商过程&#xff09;小结&#xff1a; Multi-Paxos算法关于 Multi-Paxos 的思考领导者优化Basic PaxosChubby 的 Multi-Paxos 实现小结 参考 Paxos算法 Paxos论文 Paxos Made Simple 、author&#xff1a;Lesli…