0%

HBase客户端API

HBase Java API 实战:连接、增删改查、过滤器、计数器,一套代码全搞定

HBase 的 Java API 不复杂,核心就几个类:

管什么
Connection 连集群(线程安全,全局一个)
Admin 建表、删表、改表结构
Table 增删改查数据
Put / Get / Delete / Scan 各操作的参数封装

环境准备与连接管理

在使用 HBase API 前,需确保项目引入 HBase 依赖(以 Maven 为例),并正确配置 HBase 连接信息(hbase-site.xml 需放在项目 classpath 下)。

依赖引入

1
2
3
4
5
<dependency>  
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.2.7</version> <!-- 与 HBase 集群版本一致 -->
</dependency>

连接初始化:全局一个 Connection

Connection 是线程安全的,整个应用生命周期里用一个就行,不要每次操作都 new。

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
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.TableName;

public class HBaseClient {
// 全局连接(线程安全,单例)
private static Connection connection;
private static Table table;

static {
try {
// 自动加载 classpath 下的 hbase-site.xml
connection = ConnectionFactory.createConnection();
table = connection.getTable(TableName.valueOf("test"));
} catch (IOException e) {
throw new RuntimeException("HBase 连接初始化失败", e);
}
}

// 如果操作多张表,用这个方法获取 Table 实例
public static Table getTable(String tableName) throws IOException {
return connection.getTable(TableName.valueOf(tableName));
}
}

关键点: ConnectionFactory.createConnection() 会自动读取 hbase-site.xml,把它放在 src/main/resources 下就行。

插入数据(Put)

1
2
3
4
5
6
7
8
9
10
public static void putData(String rowKey, String family, String qualifier, String value) 
throws IOException {
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(
Bytes.toBytes(family),
Bytes.toBytes(qualifier),
Bytes.toBytes(value)
);
table.put(put);
}

调用:

1
2
3
putData("user_001", "info", "name", "张三");
putData("user_001", "info", "age", "25");
putData("user_001", "log", "login_time", "2024-01-15 08:00:00");

批量插入(性能更好):

1
2
3
public static void batchPut(List<Put> puts) throws IOException {
table.put(puts);
}

查询单行(Get)

1
2
3
4
5
6
7
8
9
public static String getData(String rowKey, String family, String qualifier) 
throws IOException {
Get get = new Get(Bytes.toBytes(rowKey));
get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));

Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes(family), Bytes.toBytes(qualifier));
return value == null ? null : Bytes.toString(value);
}

调用:

1
2
String name = getData("user_001", "info", "name");
System.out.println(name); // 张三

查整行(不加列过滤):

1
2
3
4
5
6
7
8
9
Get get = new Get(Bytes.toBytes(rowKey));
Result result = table.get(get);
// 遍历所有列
for (Cell cell : result.listCells()) {
String family = Bytes.toString(CellUtil.cloneFamily(cell));
String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
String value = Bytes.toString(CellUtil.cloneValue(cell));
System.out.println(family + ":" + qualifier + " = " + value);
}

删除数据(Delete)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 删除单列
public static void deleteColumn(String rowKey, String family, String qualifier)
throws IOException {
Delete delete = new Delete(Bytes.toBytes(rowKey));
delete.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
table.delete(delete);
}

// 删除整行
public static void deleteRow(String rowKey) throws IOException {
Delete delete = new Delete(Bytes.toBytes(rowKey));
table.delete(delete);
}

批量扫描(Scan)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void scanData(String family, String qualifier, int limit) 
throws IOException {
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));

// 分页:只返回前 limit 行
if (limit > 0) {
scan.setFilter(new PageFilter(limit));
}

try (ResultScanner scanner = table.getScanner(scan)) {
for (Result result : scanner) {
String rowKey = Bytes.toString(result.getRow());
String value = Bytes.toString(
result.getValue(Bytes.toBytes(family), Bytes.toBytes(qualifier))
);
System.out.println("RowKey: " + rowKey + ", Value: " + value);
}
}
}

范围扫描:

1
2
3
Scan scan = new Scan();
scan.withStartRow(Bytes.toBytes("user_001"));
scan.withStopRow(Bytes.toBytes("user_100"));

计数器(原子累加)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static long increment(String rowKey, String family, String qualifier, long delta) 
throws IOException {
return table.incrementColumnValue(
Bytes.toBytes(rowKey),
Bytes.toBytes(family),
Bytes.toBytes(qualifier),
delta // 步长,可正可负
);
}

// 查看当前值(delta=0 不改变值)
public static long getCounter(String rowKey, String family, String qualifier)
throws IOException {
return table.incrementColumnValue(
Bytes.toBytes(rowKey),
Bytes.toBytes(family),
Bytes.toBytes(qualifier),
0
);
}

调用:

1
2
3
4
5
6
7
// 累加 +1
increment("ad_001", "stats", "impression", 1);
// 累加 +5
increment("ad_001", "stats", "impression", 5);
// 查当前值
long count = getCounter("ad_001", "stats", "impression");
System.out.println("曝光量: " + count);

计数器是原子操作,多个客户端同时累加不会乱。

资源管理:用 try-with-resources

TableResultScanner 需要关闭,用 try-with-resources 最省事:

1
2
3
4
5
6
7
8
9
10
11
//  推荐
try (Table table = connection.getTable(TableName.valueOf("test"))) {
// 操作 table
} catch (IOException e) {
// 处理异常
}

// 不推荐:手动 close,容易漏
Table table = connection.getTable(...);
// 操作...
table.close(); // 万一中间抛异常,close 不执行

全局 Connection 在应用关闭时释放:

1
2
3
4
5
6
7
8
9
// 应用关闭时调用
public static void close() {
try {
if (table != null) table.close();
if (connection != null) connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}

完整代码结构

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.filter.PageFilter;
import java.io.IOException;

public class HBaseClient {
private static Connection connection;

static {
try {
connection = ConnectionFactory.createConnection();
} catch (IOException e) {
throw new RuntimeException("HBase 连接失败", e);
}
}

// 获取 Table 实例(每次用 try-with-resources)
public static Table getTable(String tableName) throws IOException {
return connection.getTable(TableName.valueOf(tableName));
}

// ---- 增删改查 ----
public static void putData(String tableName, String rowKey, String family,
String qualifier, String value) throws IOException {
try (Table table = getTable(tableName)) {
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier), Bytes.toBytes(value));
table.put(put);
}
}

public static String getData(String tableName, String rowKey, String family,
String qualifier) throws IOException {
try (Table table = getTable(tableName)) {
Get get = new Get(Bytes.toBytes(rowKey));
get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes(family), Bytes.toBytes(qualifier));
return value == null ? null : Bytes.toString(value);
}
}

public static void deleteData(String tableName, String rowKey, String family,
String qualifier) throws IOException {
try (Table table = getTable(tableName)) {
Delete delete = new Delete(Bytes.toBytes(rowKey));
delete.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
table.delete(delete);
}
}

public static long increment(String tableName, String rowKey, String family,
String qualifier, long delta) throws IOException {
try (Table table = getTable(tableName)) {
return table.incrementColumnValue(
Bytes.toBytes(rowKey),
Bytes.toBytes(family),
Bytes.toBytes(qualifier),
delta
);
}
}

public static void close() {
try {
if (connection != null) connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) throws IOException {
String tableName = "test";

// 插入
putData(tableName, "user_001", "info", "name", "张三");

// 查询
String name = getData(tableName, "user_001", "info", "name");
System.out.println("姓名: " + name);

// 计数器
long count = increment(tableName, "ad_001", "stats", "impression", 1);
System.out.println("计数: " + count);

// 清理
close();
}
}

欢迎关注我的其它发布渠道