目录

  • HBaseUtil工具类
  • API介绍
  • 获取表
  • 存储数据
  • 获取数据
  • 批量存储数据
  • 批量获取数据
  • 删除数据
  • 最终代码


HBaseUtil工具类

前面我们实现了Flink整合Kafka,可以从Kafka中获取数据进行分析,分析之后我们要把结果存入HBase中,为了方便操作,我们先提前编写一个操作HBase的工具类。HBase作为一个数据库,我们肯定要进行数据的增删改查,那么我们就围绕这几个操作进行开发。

flink数据输出到hbase flink读取hbase_数据

API介绍

先来看下我们要编写的工具类的所有方法,我们先明确了目标,再进行开发。

方法名

用途

参数说明

返回值

getTable

创建/获取表

tableNameStr:表名

columnFamily:列族名

HBase Table对象

putData

插入/更新一列数据

tableNameStr: 表名

rowkey:String rowkey

columnFamily:列族名

column:String 列名

data:String 列值


putMapData

插入/更新多个列数据

tableNameStr: 表名

rowkey:String rowkey

columnFamily:列族名

mapData:列名/列值


getData

根据rowkey,列族+列名

获取单列数据

tableNameStr: 表名

rowkey:String rowkey

columnFamily:列族名

column:列名

列对应的数据

String类型

getMapData

根据rowkey,列族+列名集合

获取多列数据

tableNameStr: 表名

rowkey:String rowkey

columnFamily:列族名

column:列名集合

列对应的数据

Map[列名, 列值]

deleteData

根据rowkey删除一条数据

tableNameStr: 表名

rowkey:rowkey

columnFamily: 列族名


HBase操作基本类

类名

用途

获取方式




Configuration

HBase的配置类

HBaseConfiguration.create

Connection

连接

ConnectionFactory.createConnection(conf)

Admin

HBase的操作API

Connection.getAdmin

Table

用来链接HBase的单表

Connection.getTable()

Get

用来查询HBase的单行数据

new Get(rowkey.getBytes())

Put

保存单行数据

new Put(rowkey.getBytes())

Delete

删除单行数据

new Delete(rowkey.getBytes())

获取表

开发步骤:

  1. 将导入hbase-site.xml
    置文件到resources目录
  2. util包中添加HBaseUtil
  • 使用HBaseConfiguration.create获取配置对象Configuration,该配置对象会自动加载hbase-site.xml
  • 使用ConnectionFactory.createConnection获取hbase连接
  • 使用Connection.getAdmin获取与master的连接
  1. 创建getTable方法
  • 构建TableName
  • 构建TableDescriptorBuilder
  • 构建ColumnFamilyDescriptor
  • 添加列族
  • 检查表是否存在,若不存在,则创建表
    源码解析:
    我们可以围绕Admin来展开源码的查看,请观察下图,通过源码的注释,我们可以很简单的找到该编写的代码。

    示例代码:
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client._

object HBaseUtil {

  // 读取配置文件
  val conf: Configuration = HBaseConfiguration.create

  // 创建连接
  val conn: Connection = ConnectionFactory.createConnection(conf)

  // 创建HBase管理类
  val admin: Admin = conn.getAdmin

  /**
    * 获得表,如果表不存在则创建
    *
    * @param tableNameStr     表名
    * @param columnFamilyName 列族名
    * @return
    */
  def getTable(tableNameStr: String, columnFamilyName: String): Table = {

    // 获取 TableName
    val tableName: TableName = TableName.valueOf(tableNameStr)

    //判断表是否可用
    if (!admin.tableExists(tableName)) {
      // 构建TableDescriptorBuilder
      val tableDescriptor: TableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName)

      // 构建列族 ColumnFamilyDescriptor
      val columnFamily: ColumnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(columnFamilyName.getBytes).build()
      tableDescriptor.setColumnFamily(columnFamily)
      // 创建表
      admin.createTable(tableDescriptor.build())
    }

    // 返回表
    conn.getTable(tableName)
  }

存储数据

创建putData方法

  • 调用getTable获取表
  • 构建Put对象
  • 添加列、列值
  • 对table执行put操作
  • 启动编写main进行测试
/**
    * 保存数据
    *
    * @param tableNameStr     表名
    * @param rowkey           rowkey
    * @param columnFamilyName 列族名
    * @param columnName       列名
    * @param columnValue      列值
    */
def putData(tableNameStr: String,
            rowkey: String,
            columnFamilyName: String,
            columnName: String,
            columnValue: String
           ) = {
    val table = getTable(tableNameStr, columnFamilyName)

    try {
        // Put
        val put = new Put(rowkey.getBytes())
        // 参数1: 列族 参数2: 列名 参数3: 列值
        put.addColumn(columnFamilyName.getBytes, columnName.getBytes, columnValue.getBytes)
        // 保存数据
        table.put(put)
    } catch {
        case ex: Exception => {
            ex.printStackTrace()
        }
    } finally {
        // 关闭table
        table.close()
    }
}

获取数据

  1. 使用Connection获取表
  2. 创建getData方法
  • 调用getTable获取表
  • 构建Get对象
  • 对table执行get操作,获取result
  • 使用Result.getValue获取列族列对应的值
  • 捕获异常
  • 关闭表
  1. 启动hhbase
  2. 启动编写main进行测试
/**
    * 查询数据
    *
    * @param tableNameStr     表名
    * @param rowkey           rowkey
    * @param columnFamilyName 列族名
    * @param columnName       列名
    */
def getData(tableNameStr: String,
            rowkey: String,
            columnFamilyName: String,
            columnName: String) = {

    val table: Table = getTable(tableNameStr, columnFamilyName)

    try {

        // Get对象
        val get: Get = new Get(rowkey.getBytes)
        // 查询结果
        val result = table.get(get)
        // 结果不为空, 并且结果包含我们要查询的列
        if (result != null && result.containsColumn(columnFamilyName.getBytes, columnName.getBytes)) {
            // - 使用Result.getValue获取列族列对应的值
            val colValueBytes: Array[Byte] = result.getValue(columnFamilyName.getBytes, columnName.getBytes)
            Bytes.toString(colValueBytes)
        }else {
        ""
      	}
    } catch {
        case ex: Exception =>
        ex.printStackTrace()
        ""
    } finally {
        // - 关闭表
        table.close()
    }
}

批量存储数据

创建putMapData方法

  • 调用getTable获取表
  • 构建Put对象
  • 添加Map中的列、列值
  • 对table执行put操作
  • 捕获异常
  • 关闭表
  • 启动编写main进行测试
/**
    * 批量存储数据
    *
    * @param tableNameStr     表名
    * @param rowkey           rowkey
    * @param columnFamilyName 列族名
    * @param map              key/value集合
    */
def putMapData(tableNameStr: String,
               rowkey: String,
               columnFamilyName: String,
               map: Map[String, Any]
              ) = {
    val table = getTable(tableNameStr, columnFamilyName)

    try {
        //- 添加Map中的列、列值
        for ((columnName, columnValue) <- map) {
            // Put
            val put = new Put(rowkey.getBytes())
            put.addColumn(columnFamilyName.getBytes, columnName.getBytes, columnValue.toString.getBytes)
            table.put(put)
        }

    } catch {
        case ex: Exception => {
            ex.printStackTrace()
        }
    } finally {
        table.close()
    }
}

批量获取数据

创建putMapData方法

  • 调用getTable获取表
  • 构建Get对象
  • 根据Get对象查询表
  • 构建可变Map
  • 遍历查询各个列的列值
  • 过滤掉不符合的结果
  • 把结果转换为Map返回
  • 捕获异常
  • 关闭表
  • 启动编写main进行测试
/**
    * 批量获取列的数据
    *
    * @param tableNameStr 表名
    * @param rowkey       rowkey
    * @param columnFamily 列族
    * @param columnList   列的名字列表
    * @return
    */
def getMapData(tableNameStr: String, rowkey: String, columnFamily: String, columnList: List[String]): Map[String, String] = {
    // 根据表名和列族名获取表
    val table: Table = getTable(tableNameStr, columnFamily)

    try {
        // 创建Get对象
        val get: Get = new Get(rowkey.getBytes)

        // 根据Get对象查询表
        val result: Result = table.get(get)

        // 构建可变Map
        val valueMap = collection.mutable.Map[String, String]()

        // 遍历要查询的列集合
        columnList.map {
            col =>
            // 从表查询结果中,根据列族,列名提取出列值
            val values: Array[Byte] = result.getValue(columnFamily.getBytes, col.getBytes)

            // 列值不为空 , 则设置 k-> v
            if (values != null && values.size > 0) {
                col -> Bytes.toString(values)
            }
            else {
                "" -> ""
            }
        }.filter(_._1 != "").toMap  // 过滤掉key为""的内容,并转换为Map类型
    } catch {
        case e: Exception =>
        e.printStackTrace()
        Map[String, String]()
    } finally {
        table.close()
    }
}

删除数据

创建deleteData方法

  • 调用getTable获取表
  • 构建Delete对象
  • 对table执行delete操作
  • 捕获异常
  • 关闭表
  • 启动编写main进行测试
/**
   * 删除数据
   *
   * @param tableNameStr     表名
   * @param columnFamilyName 列族名
   * @param rowkey           rowkey
   */
  def deleteData(tableNameStr: String,
                 rowkey: String,
                 columnFamilyName: String
                ) = {
    // 获取表
    val table = getTable(tableNameStr, columnFamilyName)
    try {
      // 创建Delete对象
      val delete = new Delete(rowkey.getBytes)
      table.delete(delete)
    } catch {
      case ex: Exception =>
        ex.printStackTrace()
    } finally {
      table.close()
    }
  }

main方法测试代码

object HBaseUtil {
    
    def main(args: Array[String]): Unit = {
    // 测试存入单列数据
    putData("test", "123", "info", "t1", "hello world")

    // 测试存入多列数据
    val map = Map(
      "t2" -> "scala",
      "t3" -> "hive",
      "t4" -> "sqoop"
    )
    putMapData("test", "123", "info", map)

    println(getData("test", "123", "info", "t1"))
    println(getData("test", "123", "info", "t2"))
    println(getData("test", "123", "info", "t3"))
    println(getData("test", "123", "info", "t4"))
        
    println(getMapData("test", "123", "info", List("t1", "t2","t3","t4")))

    deleteData("test", "123", "info")
  }

}

最终代码

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client.{Admin, ColumnFamilyDescriptorBuilder, Connection, ConnectionFactory, Delete, Get, Put, Result, Table, TableDescriptor, TableDescriptorBuilder}
import org.apache.hadoop.hbase.util.Bytes


/**
 * HBase工具类
 *
 * 获取Table
 * 保存单列数据
 * 查询单列数据
 * 保存多列数据
 * 查询多列数据
 * 删除数据
 */
object HBaseUtil {

  //HBase的配置类,不需要指定配置文件名,文件名要求是hbase-site.xml
  val conf:Configuration = HBaseConfiguration.create()

  //hbase的连接
  val conn:Connection = ConnectionFactory.createConnection()

  //hbase的api
  val admin:Admin = conn.getAdmin

  /**
   * 返回table,如果不存在,则创建表
   * @param tableNameStr
   * @param columnFamilyName
   * @return
   */
  def getTable(tableNameStr:String,columnFamilyName:String):Table={

    //获取TableName
    val tableName = TableName.valueOf(tableNameStr)

    //如果表不存在,则创建表
    if (!admin.tableExists(tableName)){

      //构建出 表的描述的建造者
      val descBuilder = TableDescriptorBuilder.newBuilder(tableName)

      val familyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(columnFamilyName.getBytes).build()
      //给表去添加列族
      descBuilder.setColumnFamily(familyDescriptor)

      //创建表
      admin.createTable(descBuilder.build())
    }
    conn.getTable(tableName)
  }

  /**
   *存储单列数据
   * @param tableNameStr       表名
   * @param rowkey             rowkey
   * @param columnFamilyName   列族名
   * @param columnName         列名
   * @param columnValue        列值
   */
  def putData(tableNameStr:String,rowkey:String,columnFamilyName:String,columnName:String,columnValue:String): Unit ={

    //获取表
    val table = getTable(tableNameStr, columnFamilyName)

    try{
      //Put
      val put = new Put(rowkey.getBytes())
      put.addColumn(columnFamilyName.getBytes(),columnName.getBytes(),columnValue.getBytes())

      //保存数据
      table.put(put)
    }catch {
      case ex:Exception=>{
        ex.printStackTrace()
      }
    }finally {
      table.close()
    }
  }

  /**
   * 通过单列获取列值
   * @param tableNameStr      表名
   * @param rowkey            rowkey
   * @param columnFamilyName  列族名
   * @param columnName        列明
   * @return                  列值
   */
  def getData(tableNameStr: String,
              rowkey: String,
              columnFamilyName: String,
              columnName: String) = {

    val table: Table = getTable(tableNameStr, columnFamilyName)

    try {

      // Get对象
      val get: Get = new Get(rowkey.getBytes)
      // 查询结果
      val result = table.get(get)
      // 结果不为空, 并且结果包含我们要查询的列
      if (result != null && result.containsColumn(columnFamilyName.getBytes, columnName.getBytes)) {
        // - 使用Result.getValue获取列族列对应的值
        val colValueBytes: Array[Byte] = result.getValue(columnFamilyName.getBytes, columnName.getBytes)
        Bytes.toString(colValueBytes)
      }else {
        ""
      }
    } catch {
      case ex: Exception =>
        ex.printStackTrace()
        ""
    } finally {
      // - 关闭表
      table.close()
    }
  }

  /**
   * 批量存储数据
   *
   * @param tableNameStr     表名
   * @param rowkey           rowkey
   * @param columnFamilyName 列族名
   * @param map              key/value集合
   */
  def putMapData(tableNameStr: String,
                 rowkey: String,
                 columnFamilyName: String,
                 map: Map[String, Any]
                ) = {
    val table = getTable(tableNameStr, columnFamilyName)

    try {
      //- 添加Map中的列、列值
      for ((columnName, columnValue) <- map) {
        // Put
        val put = new Put(rowkey.getBytes())
        put.addColumn(columnFamilyName.getBytes, columnName.getBytes, columnValue.toString.getBytes)
        table.put(put)
      }

    } catch {
      case ex: Exception => {
        ex.printStackTrace()
      }
    } finally {
      table.close()
    }
  }

  /**
   * 删除数据
   *
   * @param tableNameStr     表名
   * @param columnFamilyName 列族名
   * @param rowkey           rowkey
   */
  def deleteData(tableNameStr: String,
                 rowkey: String,
                 columnFamilyName: String
                ) = {
    // 获取表
    val table = getTable(tableNameStr, columnFamilyName)
    try {
      // 创建Delete对象
      val delete = new Delete(rowkey.getBytes)
      table.delete(delete)
    } catch {
      case ex: Exception =>
        ex.printStackTrace()
    } finally {
      table.close()
    }
  }

  /**
   * 批量获取列的数据
   *
   * @param tableNameStr 表名
   * @param rowkey       rowkey
   * @param columnFamily 列族
   * @param columnList   列的名字列表
   * @return
   */
  def getMapData(tableNameStr: String, rowkey: String, columnFamily: String, columnList: List[String]): Map[String, String] = {
    // 根据表名和列族名获取表
    val table: Table = getTable(tableNameStr, columnFamily)

    try {
      // 创建Get对象
      val get: Get = new Get(rowkey.getBytes)

      // 根据Get对象查询表
      val result: Result = table.get(get)

      // 构建可变Map
      val valueMap = collection.mutable.Map[String, String]()

      // 遍历要查询的列集合
      columnList.map {
        col =>
          // 从表查询结果中,根据列族,列名提取出列值
          val values: Array[Byte] = result.getValue(columnFamily.getBytes, col.getBytes)

          // 列值不为空 , 则设置 k-> v
          if (values != null && values.size > 0) {
            col -> Bytes.toString(values)
          }
          else {
            "" -> ""
          }
      }.filter(_._1 != "").toMap  // 过滤掉key为""的内容,并转换为Map类型
    } catch {
      case e: Exception =>
        e.printStackTrace()
        Map[String, String]()
    } finally {
      table.close()
    }
  }

  def main(args: Array[String]): Unit = {
   // println(getTable("test", "info"))
   // putData("test","1","info","t1","hello")
   // println(getData("test", "1", "info", "t1"))
  /* val map = Map(
     "t2" -> "scala",
     "t3" -> "hive",
     "t4" -> "sqoop"
   )
    putMapData("test", "123", "info", map)*/

    deleteData("test", "123", "info")
    println(getMapData("test", "123", "info", List("t1", "t2","t3","t4")))
  }
}