首批通过分布式安全可靠测评,为关键业务系统打造
OBKV-HBase 数据操作示例
更新时间:2025-03-20 11:21:26
本文以具体的示例为例来介绍如果通过 OBKV-HBase 客户端进行数据处理。
说明
OBKV-HBase 客户端已支持的接口列表,参见和 HBase 的兼容性。
准备工作
基于以下示例进行体验之前,请确保您已经完成如下准备工作:
已经部署了 OceanBase 集群。关于支持的部署方案、部署方式以及详细的部署操作,参见 部署简介。
已经创建了 MySQL 租户。关于创建租户的详细操作,参见 创建租户。
已经创建了数据库。关于创建数据库的详细操作,参见 创建数据库。
已经创建了 OBKV-HBase 数据表。关于创建 OBKV-HBase 数据表的详细操作,参见 数据库模式设计。
在本示例中,表名为 htable1$family。建表示例如下。
CREATE TABLEGROUP htable1; CREATE TABLE htable1$family ( K varbinary(1024), Q varbinary(256), T bigint, V varbinary(1048576) NOT NULL, PRIMARY KEY(K, Q, T)) TABLEGROUP = htable1 ;本示例通过 OHTable 连接 OBKV-HBase 集群并进行数据处理,请确保已经完成 OBKV-HBase 客户端的部署和配置,并通过 OHTable 连接了集群。详细操作参见 使用 OBKV-HBase 客户端连接集群。
注意事项
- 代码示例中的执行结果,依赖下面各个操作的顺序,如需复现,请按照顺序执行。
- 为了比较直观的观察数据库中的结果,示例中采用 MySQL 客户端连接 OBKV-HBase,通过 SQL 来查询数据库表 htable1$family 的状态。
Put
函数说明:
- 插入数据。
函数原型:
- void put(Put put)
- void put(List
puts)
参数列表:
- put:Put 对象,用于插入单条记录。
- puts:Put 对象集合,用于批量插入多条记录。
操作示例:
// 插入单条记录
String key = "testKey0";
String family = "family";
String column = "column";
String value = "putValue";
Put put = new Put(key.getBytes());
put.add(family.getBytes(), column.getBytes(), value.getBytes());
hTable.put(put);
// 插入多条记录
Put put1 = new Put(Bytes.toBytes("testKey1"));
put1.add(toBytes(family), toBytes(column), toBytes(value));
//put1.add(toBytes(family), toBytes(column), System.currentTimeMillis(), toBytes(value));
Put put2 = new Put(Bytes.toBytes("testKey2"));
put2.add(toBytes(family), toBytes(column), toBytes(value));
//put2.add(toBytes(family), toBytes(column), System.currentTimeMillis(), toBytes(value));
List<Put> puts = new ArrayList<Put>();
puts.add(put1);
puts.add(put2);
hTable.put(puts);
MySQL [test]> select * from htable1$family;
+----------+--------+----------------+----------+
| K | Q | T | V |
+----------+--------+----------------+----------+
| testKey0 | column | -1715961035391 | putValue |
| testKey1 | column | -1715961035471 | putValue |
| testKey2 | column | -1715961035471 | putValue |
+----------+--------+----------------+----------+
备注:
- 上述示例中,向数据库中插入了 3 个 Cell。
Get
函数说明:
- 获取指定行的数据。
函数原型:
- Result get(final Get get)
- Result[] get(List
gets)
参数列表:
- get:Get 对象,需要使用 addColumn 或 addFamily 来指定操作目标。
- gets:Get 对象列表,保存 Get 对象。
操作示例:
// 获取 one family
String key = "testKey0";
String family = "family";
int maxVersion = 1;
Get get = new Get(key.getBytes());
get.addFamily(family.getBytes());
get.setMaxVersions(maxVersion);
Result result = hTable.get(get);
if (result.list() != null) {
System.out.printf("Get Demo: get cnt:%d%n", result.list().size());
}
String key = "testKey0";
Get get = new Get(key.getBytes());
Result result = hTable.get(get);
if (result.list() != null) {
System.out.printf("Get Demo: get cnt:%d%n", result.list().size());
}
MySQL [test]> select * from htable1$family where k = "testKey0";
+----------+--------+----------------+----------+
| K | Q | T | V |
+----------+--------+----------------+----------+
| testKey0 | column | -1715961561057 | putValue |
+----------+--------+----------------+----------+
备注:
- 例子中 Get 的语义,在 HBase 的记录没有多版本的时候,等价于上述的 SQL。
- 承接于 Put 的例子,数据库中有一条主键为 testKey0 的 Cell。
Scan
函数说明:
- 根据指定条件(scan/family/qualifier)对 Table 进行扫描。
函数原型:
- ResultScanner getScanner(byte[] family, byte[] qualifier)
- ResultScanner getScanner(final byte[] family)
- ResultScanner getScanner(final Scan scan)
参数列表:
- family:目标列簇,这里是指需要过滤的列簇。
- qualifier:目标列名,这里指需要过滤的列名。
- scan:Scan 对象,使用 addFamily 或 addColumn 等设置操作目标。
操作示例:
String startKey = "testKey";
String endKey = "testKey9";
String family = "family";
String column = "column";
int maxVersion = 1;
Scan scan = new Scan();
scan.addColumn(family.getBytes(), column.getBytes());
scan.setMaxVersions(maxVersion);
scan.setStartRow(startKey.getBytes());
scan.setStopRow(endKey.getBytes());
ResultScanner scanner = hTable.getScanner(scan);
for (Result r : scanner) {
for (KeyValue kv : r.list()) {
System.out.printf("Scan Demo: Rowkey: %s, Column Family: %s, Column Qualifier: %s, Value: %s, Timestamp: %d%n",
Bytes.toString(r.getRow()),
Bytes.toString(kv.getFamily()),
Bytes.toString(kv.getQualifier()),
Bytes.toString(kv.getValue()),
kv.getTimestamp());
}
}
返回结果如下:
+----------+--------+----------------+----------+
| K | Q | T | V |
+----------+--------+----------------+----------+
| testKey0 | column | -1715961561057 | putValue |
| testKey1 | column | -1715961561132 | putValue |
| testKey2 | column1 | -1715961561132 | putValue |
| testKey2 | column2 | -1715961561132 | putValue |
OBKV-HBase 支持 Reverse Scan 功能,它允许用户以行键(RowKey)逆序(从大到小)扫描表中的数据,这与常规的正序(从小到大)扫描相反。上条示例逆序扫描示例如下:
String startKey = "testKey9";
String endKey = "testKey";
String family = "family";
String column = "column";
int maxVersion = 1;
Scan scan = new Scan();
scan.addColumn(family.getBytes(), column.getBytes());
scan.setMaxVersions(maxVersion);
scan.setStartRow(startKey.getBytes());
scan.setStopRow(endKey.getBytes());
// 设置启用 Reverse scan
scan.setReversed(true);
ResultScanner scanner = hTable.getScanner(scan);
for (Result r : scanner) {
for (KeyValue kv : r.list()) {
System.out.printf("Scan Demo: Rowkey: %s, Column Family: %s, Column Qualifier: %s, Value: %s, Timestamp: %d%n",
Bytes.toString(r.getRow()),
Bytes.toString(kv.getFamily()),
Bytes.toString(kv.getQualifier()),
Bytes.toString(kv.getValue()),
kv.getTimestamp());
}
}
结果如下:
+----------+--------+----------------+----------+
| K | Q | T | V |
+----------+--------+----------------+----------+
| testKey2 | column1 | -1715961561132 | putValue |
| testKey2 | column2 | -1715961561132 | putValue |
| testKey1 | column | -1715961561132 | putValue |
| testKey0 | column | -1715961561057 | putValue |
备注:
- 例子中 Scan 的语义,在 HBase 的记录没有多版本的时候,等价于上述的 SQL。
- 注意 HBase 0.94 的 start 和 endkey 是左闭右开,endkey 扫不到。
- 承接于 Put 的例子,数据库中有 3 条满足条件的 Cell。
Increment Column Value
函数说明:
- 对表中的某行单列数据进行自增,执行成功则返回自增后的值,指定列的 cell 必须是 long 类型(64 字节整型)。
函数原型:
- long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier, long amount, boolean writeToWAL)
参数列表:
- row:行键。
- family:目标列簇,这里是建表时指定的列簇。
- qualifier:目标列名。
- amount:增加的数量(可以为负值)。
- writeToWAL:是否预写日志,OBKV-HBase 不需要设置。
操作示例:
// 这里展示的是对单列自增 1
String column = "incrementColumn";
String key = "incrementKey";
String family = "family";
long increment_value = 1L;
long ret = hTable.incrementColumnValue(
key.getBytes(),
family.getBytes(),
column.getBytes(),
increment_value);
System.out.printf("Increment Column Demo: ret: %b%n", ret);
MySQL [test]> select *,hex(v) from htable1$family where k = "incrementKey";
+--------------+-----------------+----------------+----------+------------------+
| K | Q | T | V | hex(v) |
+--------------+-----------------+----------------+----------+------------------+
| incrementKey | incrementColumn | -1715961669857 | | 0000000000000001 |
+--------------+-----------------+----------------+----------+------------------+
备注:
- 如果使用 MySQL 客户端查看 HBase 表,可能会发现对应 Cell 的 V 字段没有值,可以用 hex(v) 来显示。
- 如上,Increment 的行为是如果数据库中查询不到满足条件的 Cell,那么会生成一个 Cell,值默认为 0,接着进行 Increment。
Increment
函数说明:
- 对指定行中的单列或多列进行增加,指定列的 cell 必须是 long 类型(64 字节整型)。
函数原型:
- Result increment(Increment increment)
参数列表:
- increment: Increment 类型,需要使用 addColumn 进行属性设置。
操作示例:
// 这里展示的是对单列自增 1
String column = "incrementColumn";
String key = "incrementKey";
String family = "family";
long increment_value = 1L;
Increment increment = new Increment(key.getBytes());
increment.addColumn(family.getBytes(), column.getBytes(), increment_value);
Result r = hTable.increment(increment);
for (KeyValue kv : r.list()) {
System.out.printf("Increment Demo: Rowkey: %s, Value:%s%n",
Bytes.toString(r.getRow()),
Bytes.toLong(kv.getValue()));
}
MySQL [test]> select *,hex(v) from htable1$family where k = "incrementKey";
+--------------+-----------------+----------------+----------+------------------+
| K | Q | T | V | hex(v) |
+--------------+-----------------+----------------+----------+------------------+
| incrementKey | incrementColumn | -1715961734681 | | 0000000000000002 |
| incrementKey | incrementColumn | -1715961669857 | | 0000000000000001 |
+--------------+-----------------+----------------+----------+------------------+
备注:
- 如上,对一个 Cell 多次做自增,会产生多个版本的 Cell。HBase 中没有 Update 的操作语义,对一个 Cell 的修改会变成多版本,用户可以指定版本来做查询。
Append
函数说明:
- 对指定行中的单列或多列进行增加(针对字符类型,例如 byte,string 等)。
函数原型:
- Result append(Append append)
参数列表:
- append:Append 类型,需要使用 add 函数进行属性设置。
操作示例:
String column = "appendColumn";
String key = "appendKey";
String family = "family";
Append append = new Append(key.getBytes());
append.add(family.getBytes(), column.getBytes(), toBytes("_append"));
Result r = hTable.append(append);
for (KeyValue kv : r.list()) {
System.out.printf("Appand Demo: Rowkey: %s, Append Value:%s%n",
Bytes.toString(r.getRow()),
Bytes.toString(kv.getValue()));
}
MySQL [test]> select * from htable1$family where k = "appendKey";
+-----------+--------------+----------------+---------+
| K | Q | T | V |
+-----------+--------------+----------------+---------+
| appendKey | appendColumn | -1715961265748 | _append |
+-----------+--------------+----------------+---------+
备注:
- 如上,Append 的行为是如果数据库中查询不到满足条件的 Cell,那么会插入对应的 Cell,值默认为空串,接着对生成的记录进行 Append 操作。
Delete
函数说明:
- 删除指定的存储单元(cells)或行(rows)。
函数原型:
- void delete(Delete delete)
- void delete(List
deletes)
参数列表:
- deletes:Delete 对象,这里是指需要执行删除的行,通过 deleteFamily 函数设置。
操作示例:
// 如下是删除某 key,family,column 对应的行
String key = "testKey1";
String family = "family";
String column = "column";
Delete delete = new Delete(key.getBytes());
delete.deleteColumn(family.getBytes(),column.getBytes());
hTable.delete(delete);
MySQL [test]> select * from htable1$family;
+--------------+-----------------+----------------+----------+
| K | Q | T | V |
+--------------+-----------------+----------------+----------+
| appendKey | appendColumn | -1715961265748 | _append |
| incrementKey | incrementColumn | -1715961228139 | |
| incrementKey | incrementColumn | -1715961188112 | |
| testKey0 | column | -1715961035391 | putValue |
| testKey2 | column | -1715961035471 | putValue |
+--------------+-----------------+----------------+----------+
备注:
- 查询整张表的状态,发现主键为 testKey1 的 Cell 都被删除了。
Exists
函数说明:
- 判断在 Get 对象中设置的列簇或列是否存在,存在则返回 true,反之返回 false。
函数原型:
- boolean exists(Get get)
参数列表:
- get:Get 对象,使用 addFamily 或 addColumn 来设置操作目标。
操作示例:
String key = "testKey2";
String family = "family";
Get get = new Get(key.getBytes());
get.addFamily(family.getBytes());
boolean ret = hTable.exists(get);
System.out.printf("Exist Demo: ret: %b%n", ret);
MySQL [test]> select * from htable1$family where k = "testKey2";
+----------+--------+----------------+----------+
| K | Q | T | V |
+----------+--------+----------------+----------+
| testKey2 | column | -1715961561132 | putValue |
+----------+--------+----------------+----------+
备注:
- Exist 语义等同于 Get。
Check And Put
函数说明:
- 检查并替换指定列数据,如果条件满足并替换成功,返回 true,反之返回 false。
函数原型:
- boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier, byte[] value, Put put)
参数列表:
- row:目标行键。
- family:目标列簇。
- qualifier:目标列名。
- value:目标列值。
- put:需要替换的列值。
操作示例:
String key = "testKey2";
String family = "family";
String column = "column";
String value = "putValue";
String new_value = "value_new";
Put put = new Put(key.getBytes());
put.add(family.getBytes(), column.getBytes(), new_value.getBytes());
boolean ret = hTable.checkAndPut(
key.getBytes(),
family.getBytes(),
column.getBytes(),
value.getBytes(),
put);
System.out.printf("CheckAndPut Demo: ret: %b%n", ret);
MySQL [test]> select * from htable1$family where k = "testKey2";
+----------+--------+----------------+-----------+
| K | Q | T | V |
+----------+--------+----------------+-----------+
| testKey2 | column | -1715961408587 | value_new |
| testKey2 | column | -1715961035471 | putValue |
+----------+--------+----------------+-----------+
备注:
- 将满足条件的,主键为 testKey2,值为 putValue 的Cell,做了修改,生成一个值为 value_new 的新版本的 Cell。
Check And Delete
函数说明:
- 匹配删除列,若匹配条件符合并删除成功,返回 true,反之返回 false。
函数原型:
- boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier, byte[] value, Delete delete)
参数列表:
- row:目标匹配行键。
- family:目标列簇,这里是建表时指定的列簇。
- qualifier:目标匹配列名。
- value:目标匹配列值。
- delete:预期需要删除的列。
操作示例:
String key = "testKey2";
String family = "family";
String column = "column";
String value = "value_new";
Delete delete = new Delete(key.getBytes());
delete.deleteColumn(family.getBytes(), column.getBytes());
boolean ret = hTable.checkAndDelete(
key.getBytes(),
family.getBytes(),
column.getBytes(),
value.getBytes(),
delete);
System.out.printf("CheckAndDelete Demo: ret: %b%n", ret);
MySQL [test]> select * from htable1$family where k = "testKey2";
+----------+--------+----------------+----------+
| K | Q | T | V |
+----------+--------+----------------+----------+
| testKey2 | column | -1715961035471 | putValue |
+----------+--------+----------------+----------+
备注:
- 将满足条件的,主键为 testKey2,值为 value_new 的 Cell,做了删除,数据库中不存在这个 Cell。
Get Configuration
函数说明:
- 返回操作实例中的 config 句柄,可用于在操作中变更属性。
函数原型:
- Configuration getConfiguration()
参数列表:
- 无
操作示例:
hTable.getConfiguration().set("rpc.execute.timeout", "1500");