Hbase Java API原理介绍

1.0 Hbase原理及基本说明

​HBase 数据模型的关键在于稀疏、分布式、多维、排序的映射。其中映射 map指代非关系型数据库的 key-Value 结构。

Hbase存储数据的原貌:

<pre class="prettyprint hljs ruby" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">"office_info":{         #列族
"tel":"010-1111111",    #tel列
"address":"atguigu"     #address列
}

数据模型介绍

(1)Name Spase数据模型:相当于Mysql中的database,下面可以存放多张表

(2)Table:相当于数据库中的表

(3)Row:HBase 表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey

​ 的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以 RowKey 的设计十分重要。

(4)Column:每个列都由 Column Family(列族)和 Column Qualifier(列限定符)进行限定,例如 info: name,info:age。建表时,只需指明列族,而列限定符无需预先定义。

(5)Time Stamp:用于标识数据的不同版本(version),每条数据写入时,系统会自动为其加上该字段,

​ 其值为写入 HBase 的时间。

(6)Cell:由{rowkey, column Family:column Qualifier, timestamp} 唯一确定的单元。cell 中的数

​ 据全部是字节码形式存贮。

架构说明:

1)Master

实现类为 HMaster,负责监控集群中所有的 RegionServer 实例。主要作用如下:

(1)管理元数据表格 hbase:meta,接收用户对表格创建修改删除的命令并执行

(2)监控 region 是否需要进行负载均衡,故障转移和 region 的拆分。

通过启动多个后台线程监控实现上述功能:

①LoadBalancer 负载均衡器

​ 周期性监控 region 分布在 regionServer 上面是否均衡,由参数 hbase.balancer.period 控制周期时间,默认 5 分钟。

②CatalogJanitor 元数据管理器

​ 定期检查和清理 hbase:meta 中的数据。meta 表内容在进阶中介绍。

③MasterProcWAL master 预写日志处理器

​ 把 master 需要执行的任务记录到预写日志 WAL 中,如果 master 宕机,让 backupMaster读取日志继续干。

2)Region Server

Region Server 实现类为 HRegionServer,主要作用如下:

(1)负责数据 cell 的处理,例如写入数据 put,查询数据 get 等

(2)拆分合并 region 的实际执行者,有 master 监控,有 regionServer 执行。

3)Zookeeper

​ HBase 通过 Zookeeper 来做 master 的高可用、记录 RegionServer 的部署信息、并且存储有 meta 表的位置信息。 HBase 对于数据的读写操作时直接访问 Zookeeper 的,在 2.3 版本推出 Master Registry模式,客户端可以直接访问 master。使用此功能,会加大对 master 的压力,减轻对 Zookeeper的压力。

4)HDFS

​ HDFS 为 Hbase 提供最终的底层数据存储服务,同时为 HBase 提供高容错的支持。

2.0HbaseAPI的使用

2.1创建连接

​ HBase 的客户端连接由 ConnectionFactory 类来创建,用户使用完成之后需要 手动关闭连接 。同时连接是一个重量级的,推荐 一个进程使用一个连接 ,对 HBase的命令通过连接中的两个属性 Admin 和 Table 来实现 。使用类 单例模式 ,确保使用一个连接, 可以同时用于多个线程 。

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import java.io.IOException;

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();
    }

}

​<mark>还记得静态代码块的特点吗? 随着类的加载而执行,而且只执行一次</mark>

​ 静态代码块 :执行优先级高于非静态的初始化块,它会在类初始化的时候执行一次,执行完成便销毁,它仅能初始化类变量

2.2创建命名空间

在同一个包下创建HbaseDDL类,执行创建命名空间的功能,使用建造者模式

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;

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 namespase
     * admin的连接是轻量级的,不是线程安全的,不推荐池化或者缓存连接
     */
    public  static  void  createNamespace(String namespace)  throws  IOException  { 
        //1.获取admin
        Admin admin = connection.getAdmin();

        //2.调用方法创建命名空间,给一个描述
        //代码相对shell更加底层,shell实现的功能,代码一定能实现

        //2.1创建命名空间描述建造者=》设计师
        NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);

        //2.2给命名空间添加需求
        builder.addConfiguration("user","fang");

        //2.3使用builder构造出对饮的创建一个命名空间描述
        admin.createNamespace(builder.build());

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

    }

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

        System.out.println("创建成功");

        //关闭Hbase连接
        HbaseConnection.closeConnection();

    }

}

执行情况:

在命令行中查看,创建过程,表示创建成功!!!

看这里,前面的代码你会发现,如果你再次执行代码就会发现会出现问题,原因是,创建的命名空间已经存在理论来说这个问题应该自己解决,并不是将异常直接抛出,可参考如下代码

<pre class="prettyprint hljs swift" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;

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 namespase
     * admin的连接是轻量级的,不是线程安全的,不推荐池化或者缓存连接
     */
    public static void createNamespace(String namespace) throws IOException { 
        //1.获取admin
        Admin admin = connection.getAdmin();

        //2.调用方法创建命名空间,给一个描述
        //代码相对shell更加底层,shell实现的功能,代码一定能实现

        //2.1创建命名空间描述建造者=》设计师
        NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);

        //2.2给命名空间添加需求
        builder.addConfiguration("user","fang");

        //2.3使用builder构造出对饮的创建一个命名空间描述
        //创建命名空间出现的问题,都属于
        try { 
            admin.createNamespace(builder.build());
        } catch (IOException e) { 
            System.out.println("命名空间已经存在");
            e.printStackTrace();
        }

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

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

        System.out.println("执行完成");

        //关闭Hbase连接
        HbaseConnection.closeConnection();

    }

}
package com.fang.hbase;

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 namespase
     * admin的连接是轻量级的,不是线程安全的,不推荐池化或者缓存连接
     */
    public static void createNamespace(String namespace) throws IOException { 
        //1.获取admin
        Admin admin = connection.getAdmin();

        //2.调用方法创建命名空间,给一个描述
        //代码相对shell更加底层,shell实现的功能,代码一定能实现

        //2.1创建命名空间描述建造者=》设计师
        NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);

        //2.2给命名空间添加需求
        builder.addConfiguration("user","fang");

        //2.3使用builder构造出对饮的创建一个命名空间描述
        //创建命名空间出现的问题,都属于
        try { 
            admin.createNamespace(builder.build());
        } catch (IOException e) { 
            System.out.println("命名空间已经存在");
            e.printStackTrace();
        }

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

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

        System.out.println("执行完成");

        //关闭Hbase连接
        HbaseConnection.closeConnection();

    }

}

2.3判断表格是否存在

自行将本代码块,放入上方代码中进行测试即可

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">/**
     * 创建表格是否存在
     * @param namespace
     * @return
     * @throws IOException
     * trur表示存在 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();
        }

        admin.close();

        //3.返回结果
        return b;
    }

执行结果:

2.5创建表格(使用HBase1.3.1版本和2.4版本有所区别)

<pre class="prettyprint hljs typescript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">/**
     * @param tableName 表格名称
     * @param families 列族名称,可以有多个
     */
    public static void createTable(String tableName,String... families) throws IOException { 

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

        //2.调用方法创建表格
        //2.1创建表格描述的建造者
        TableName tableName1 = TableName.valueOf(tableName);

        HTableDescriptor tableDescriptor=new HTableDescriptor(tableName); //表格描述器

        if (families==null||families.length==0){
  //如果没有填写列族,给一个info
            families=new String[1];
            families[0]="info";

        }

        for (String family : families) { 
            HColumnDescriptor columnDescriptor= new HColumnDescriptor(family);//列族描述器

            tableDescriptor.addFamily(columnDescriptor);
        }
        try { 
            admin.createTable(tableDescriptor);
        } catch (IOException e) { 
            System.out.println("表格已存在");
            e.printStackTrace();
        }

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

2.6插入数据

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;

import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

public class  HBaseDML  { 

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

    /**
     * @param tableName 表名
     * @param rowKey 主键
     * @param family 列族名
     * @param columnName 列名
     * @param value 值
     */
    public  static  void  putCell(String tableName,String rowKey,String family,String columnName,String value)  throws  IOException  { 
        //1.获取table
        Table table = connection.getTable(TableName.valueOf(tableName));

        //2.调用相关方法添加数据
        Put put = new Put(Bytes.toBytes(rowKey));

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

        //4.将对象写入方法
        table.put(put);

        //5.关闭table
        try { 
            table.close();
        } catch (IOException e) { 
            System.out.println("表格是否存在");
            e.printStackTrace();
        }

    }

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

        //测试添加数据
        putCell("shuju:huahua","1000","age","agga","43");
        System.out.println("其他代码");

        //关闭连接
        HbaseConnection.closeConnection();

    }
}

测试成功!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值