HBase Java API:表管理综合指南
HBase 是一个开源的、分布式的、可扩展的多维数据存储系统,构建于 Hadoop 之上。它因处理大量稀疏数据而闻名,而 HBase Java API 允许开发人员有效地管理 HBase 表。在本指南中,我们将探索如何使用 HBase Java API 来管理表、执行 CRUD 操作、处理快照等功能。
获取HBase Connection
- HBase的connection对象是一个重量级的对象,将来编写代码(Spark、Flink)的时候,避免频繁创建,使用一 个对象就OK,因为它是线程安全的
/**
* @throws IOException 如果创建连接失败,抛出异常
* @Description 初始化HBase配置并建立连接
*/
@BeforeTest
public void initHbaseConf() throws IOException {
// 创建默认的HBase配置对象
Configuration conf = HBaseConfiguration.create();
// 建立HBase连接
connection = ConnectionFactory.createConnection(conf);
// 获取Admin对象,用于表管理操作
admin = connection.getAdmin();
}
initHbaseConf
方法创建一个 HBase 配置,建立连接,并获取用于表管理的 Admin
对象。
获取HBase Admin对象
/**
* @throws IOException 如果关闭时发生错误,抛出异常
* @Description 关闭HBase连接和Admin对象
*/
@AfterTest
public void closeHbaseConnection() throws IOException {
// 关闭Admin对象
admin.close();
// 关闭HBase连接
connection.close();
}
列出所有表
- Table这个对象是一个轻量级的,用完Table需要close,因为它是非线程安全的
/**
* @Description 列出所有表的详细信息,包括表名和列族信息
* @throws IOException 如果操作失败,抛出异常
*/
@Test
public void listAllTables() throws IOException {
// 获取Admin对象
Admin admin = connection.getAdmin();
try {
// 列出所有的表
TableName[] tableNames = admin.listTableNames();
for (TableName tableName : tableNames) {
System.out.println("Table: " + tableName.getNameAsString());
// 获取表的描述信息
TableDescriptor tableDescriptor = admin.getDescriptor(tableName);
for (ColumnFamilyDescriptor cfd : tableDescriptor.getColumnFamilies()) {
System.out.println(" Column Family: " + cfd.getNameAsString());
System.out.println(" Max Versions: " + cfd.getMaxVersions());
System.out.println(" Min Versions: " + cfd.getMinVersions());
System.out.println(" Time to Live: " + cfd.getTimeToLive());
}
}
} finally {
// 关闭Admin
admin.close();
}
}
此方法使用 Admin
列出所有表及其列族属性。
启用表
可以通过以下方法启用或禁用表:
/**
* @Description 启用指定的表,并等待启用完成
* @throws IOException 如果操作失败,抛出异常
* @throws InterruptedException 如果等待过程中被中断,抛出异常
*/
public void enableTable() throws IOException, InterruptedException {
String tableName = "CLIENT_TABLE";
Admin admin = connection.getAdmin();
try {
TableName tn = TableName.valueOf(tableName);
if (!admin.isTableEnabled(tn)) {
admin.enableTable(tn);
System.out.println("Table " + tableName + " enable operation initiated.");
// 等待直到表被启用
while (!admin.isTableEnabled(tn)) {
Thread.sleep(100);
}
System.out.println("Table " + tableName + " enabled successfully.");
} else {
System.out.println("Table " + tableName + " is already enabled.");
}
} finally {
admin.close();
}
}
这些方法用于启用表,并在操作后确认其状态。
禁用表
/**
* @Description 禁用指定的表,并等待禁用完成
* @throws InterruptedException 如果等待过程中被中断,抛出异常
*/
@Test
public void disableTable() throws IOException, InterruptedException {
String tableName = "CLIENT_TABLE";
Admin admin = connection.getAdmin();
try {
TableName tn = TableName.valueOf(tableName);
if (!admin.isTableDisabled(tn)) {
admin.disableTable(tn);
System.out.println("Table " + tableName + " disable operation initiated.");
// 等待直到表被禁用
while (!admin.isTableDisabled(tn)) {
Thread.sleep(100);
}
System.out.println("Table " + tableName + " disabled successfully.");
} else {
System.out.println("Table " + tableName + " is already disabled.");
}
} finally {
admin.close();
}
}
删除指定的表
/**
* @Description 删除指定的表
* @throws IOException 如果操作失败,抛出异常
*/
@Test
public void dropTable() throws IOException {
String tableName = "CLIENT_TABLE";
Admin admin = connection.getAdmin();
try {
TableName tn = TableName.valueOf(tableName);
if (admin.tableExists(tn)) {
if (!admin.isTableDisabled(tn)) {
admin.disableTable(tn);
}
// 删除表前清除表中的所有快照
for (SnapshotDescription snapshot : admin.listSnapshots(tableName + "-*")) {
admin.deleteSnapshot(snapshot.getName());
System.out.println("Snapshot " + snapshot.getName() + " deleted successfully.");
}
admin.deleteTable(tn);
System.out.println("Table " + tableName + " deleted successfully.");
} else {
System.out.println("Table " + tableName + " does not exist.");
}
} finally {
admin.close();
}
}
修改表结构
修改现有表,例如添加或修改列族,可以使用以下方法:
/**
* @Description 修改表的结构,例如添加或修改列族
* @throws IOException 如果操作失败,抛出异常
* @throws InterruptedException 如果等待过程中被中断,抛出异常
*/
@Test
public void alterTable() throws IOException, InterruptedException {
String tableName = "CLIENT_TABLE";
String columnFamilyName = "C1";
Admin admin = connection.getAdmin();
try {
TableName tn = TableName.valueOf(tableName);
if (admin.tableExists(tn)) {
// 获取现有的表描述符
TableDescriptor tableDescriptor = admin.getDescriptor(tn);
TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor);
// 如果列族不存在,则添加新的列族
if (tableDescriptor.getColumnFamily(Bytes.toBytes(columnFamilyName)) == null) {
ColumnFamilyDescriptor columnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamilyName)).build();
builder.setColumnFamily(columnFamilyDescriptor);
System.out.println("Column family " + columnFamilyName + " added.");
} else {
System.out.println("Column family " + columnFamilyName + " already exists, altering properties if needed.");
}
// 修改表结构
admin.modifyTable(builder.build());
System.out.println("Table " + tableName + " altered successfully.");
// 等待直到表修改完成
while (admin.getDescriptor(tn).equals(tableDescriptor)) {
Thread.sleep(100);
}
System.out.println("Confirmed: Table " + tableName + " has been altered.");
} else {
System.out.println("Table " + tableName + " does not exist.");
}
} finally {
admin.close();
}
}
上述方法演示了如何向现有表添加新的列族。
获取表的描述信息
/**
* @Description 获取表的描述信息
* @throws IOException 如果操作失败,抛出异常
*/
@Test
public void describeTable() throws IOException {
String tableName = "CLIENT_TABLE"; // 可以根据需求修改具体表名
Admin admin = connection.getAdmin();
try {
TableName tn = TableName.valueOf(tableName);
if (admin.tableExists(tn)) {
TableDescriptor tableDescriptor = admin.getDescriptor(tn);
System.out.println("Table Name: " + tableDescriptor.getTableName().getNameAsString());
System.out.println("Table is Enabled: " + admin.isTableEnabled(tn));
System.out.println("Table Region Replication: " + tableDescriptor.getRegionReplication());
for (ColumnFamilyDescriptor cfd : tableDescriptor.getColumnFamilies()) {
System.out.println("Column Family: " + cfd.getNameAsString());
System.out.println("Max Versions: " + cfd.getMaxVersions());
System.out.println("Min Versions: " + cfd.getMinVersions());
System.out.println("Time to Live: " + cfd.getTimeToLive());
System.out.println("Block Size: " + cfd.getBlocksize());
System.out.println("Compression Type: " + cfd.getCompressionType());
System.out.println("Bloom Filter Type: " + cfd.getBloomFilterType());
System.out.println("Replication Scope: " + cfd.getScope());
}
} else {
System.out.println("Table " + tableName + " does not exist.");
}
} finally {
admin.close();
}
}
CRUD 操作
插入数据到 HBase 表
要在 HBase 表中插入或更新数据,我们使用 Put
对象:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 插入或更新数据
*/
@Test
public void putDataByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Put对象,指定行键
Put put = new Put(Bytes.toBytes("row1"));
// 添加单个列族和列的数据
put.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"), Bytes.toBytes("David"));
// 添加带有时间戳的数据
put.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("age"), System.currentTimeMillis(), Bytes.toBytes("30"));
// 设置写前不覆盖
put.setDurability(Durability.SKIP_WAL);
// 添加其他属性
put.setTTL(86400000); // 设置存活时间为一天 (以毫秒为单位)
// 执行插入操作
table.put(put);
// 关闭表
table.close();
}
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 批量插入数据
*/
@Test
public void batchPutByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Put对象列表
List<Put> putList = new ArrayList<>();
// 创建并添加多行数据
Put put1 = new Put(Bytes.toBytes("row2"));
put1.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"), Bytes.toBytes("Alice"));
put1.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("age"), Bytes.toBytes("28"));
putList.add(put1);
Put put2 = new Put(Bytes.toBytes("row3"));
put2.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"), Bytes.toBytes("Bob"));
put2.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("age"), Bytes.toBytes("32"));
putList.add(put2);
// 添加更多行的数据
Put put3 = new Put(Bytes.toBytes("row4"));
put3.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"), Bytes.toBytes("Charlie"));
put3.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("age"), Bytes.toBytes("25"));
put3.setTTL(604800000); // 设置存活时间为七天
putList.add(put3);
// 执行批量插入操作
table.put(putList);
// 关闭表
table.close();
}
Put
对象允许我们指定行键、列族和要插入的数据。
从 HBase 表中检索数据
要检索特定行的数据:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 获取指定行的数据
*/
@Test
public void getRowByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Get对象,指定行键
Get get = new Get(Bytes.toBytes("row1"));
// 获取特定列族的数据
get.addFamily(Bytes.toBytes("C1"));
// 获取特定列的数据
get.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"));
// 设置时间戳范围
get.setTimeRange(0, System.currentTimeMillis());
// 设置最大版本数
get.readVersions(3);
// 设置缓存以优化性能
get.setCacheBlocks(true);
// 检查是否存在指定行
if (!table.exists(get)) {
System.out.println("Row 'row1' does not exist.");
table.close();
return;
}
// 获取数据
Result result = table.get(get);
for (Cell cell : result.rawCells()) {
String family = Bytes.toString(CellUtil.cloneFamily(cell)); // 获取列族
String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell)); // 获取列名
String value = Bytes.toString(CellUtil.cloneValue(cell)); // 获取列值
System.out.println("Row: " + Bytes.toString(result.getRow()) + ", Column Family: " + family + ", Qualifier: " + qualifier + ", Value: " + value);
}
// 关闭表
table.close();
}
Get
对象用于获取指定行的数据。
扫描 HBase 表
扫描表并应用过滤器:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 扫描表数据并展示更多操作
*/
@Test
public void scanTableByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Scan对象
Scan scan = new Scan();
// 设置扫描的开始和结束行键
scan.withStartRow(Bytes.toBytes("row1"));
scan.withStopRow(Bytes.toBytes("row4"));
// 设置要扫描的列族和列
scan.addFamily(Bytes.toBytes("C1"));
scan.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"));
// 设置时间戳范围
scan.setTimeRange(0, System.currentTimeMillis());
// 设置最大版本数
scan.readVersions(2);
// 设置缓存行数以优化性能
scan.setCaching(100);
// 设置批量返回的单元格数量
scan.setBatch(10);
// 添加过滤器以筛选数据
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
// 添加列值过滤器
filterList.addFilter(new SingleColumnValueFilter(Bytes.toBytes("C1"), Bytes.toBytes("name"), CompareOperator.EQUAL, Bytes.toBytes("David")));
// 添加行键过滤器
filterList.addFilter(new RowFilter(CompareOperator.LESS, new BinaryComparator(Bytes.toBytes("row5"))));
// 添加前缀过滤器
filterList.addFilter(new PrefixFilter(Bytes.toBytes("row")));
// 设置过滤器
scan.setFilter(filterList);
// 执行扫描操作
ResultScanner scanner = table.getScanner(scan);
try {
for (Result result : scanner) {
// 输出每个行的数据
System.out.println("Found row: " + result);
// 可以对数据进行更多的操作
byte[] value = result.getValue(Bytes.toBytes("C1"), Bytes.toBytes("name"));
if (value != null) {
System.out.println("Name: " + Bytes.toString(value));
}
}
} finally {
// 关闭扫描器
scanner.close();
// 关闭表
table.close();
}
}
删除 HBase 表中的数据
要删除特定行:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 删除指定行的数据
*/
@Test
public void deleteRowByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Delete对象,指定行键
Delete delete = new Delete(Bytes.toBytes("row1"));
// 删除特定列族的数据
delete.addFamily(Bytes.toBytes("C1"));
// 删除特定列的数据
delete.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("name"));
// 设置时间戳以删除特定时间的数据
delete.addColumns(Bytes.toBytes("C1"), Bytes.toBytes("age"), System.currentTimeMillis());
// 删除指定行的所有版本
delete.addColumns(Bytes.toBytes("C1"), Bytes.toBytes("address"));
// 执行删除操作
table.delete(delete);
System.out.println("Row 'row1' deleted successfully.");
// 关闭表
table.close();
}
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 删除指定行的所有版本的数据
*/
@Test
public void deleteAllVersionsByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Delete对象,指定行键
Delete delete = new Delete(Bytes.toBytes("row1"));
// 删除指定列族中所有版本的数据
delete.addFamily(Bytes.toBytes("C1"));
// 删除指定列的所有版本的数据
delete.addColumns(Bytes.toBytes("C1"), Bytes.toBytes("name"));
// 执行删除操作
table.delete(delete);
System.out.println("All versions of row 'row1' deleted successfully.");
// 关闭表
table.close();
}
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 批量删除数据
*/
@Test
public void batchDeleteByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Delete对象列表
List<Delete> deleteList = new ArrayList<>();
// 创建并添加删除操作
Delete delete1 = new Delete(Bytes.toBytes("row2"));
delete1.addFamily(Bytes.toBytes("C1"));
deleteList.add(delete1);
Delete delete2 = new Delete(Bytes.toBytes("row3"));
delete2.addColumns(Bytes.toBytes("C1"), Bytes.toBytes("age"));
deleteList.add(delete2);
// 执行批量删除操作
table.delete(deleteList);
System.out.println("Batch delete operation completed successfully.");
// 关闭表
table.close();
}
Delete
对象指定要删除的行和列族。
count
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 统计表中行的数量
*/
@Test
public void countRowsByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Scan对象
Scan scan = new Scan();
// 设置扫描的缓存和批量大小以提高性能
scan.setCaching(500);
scan.setBatch(100);
// 执行扫描操作
ResultScanner scanner = table.getScanner(scan);
int rowCount = 0;
try {
for (Result result : scanner) {
rowCount++;
}
System.out.println("Total number of rows: " + rowCount);
} finally {
// 关闭扫描器
scanner.close();
// 关闭表
table.close();
}
}
incre
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 对指定列的值进行增量操作,类似于HBase Shell中的incr命令
*/
@Test
public void incrementColumnValue() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Increment对象,指定行键
Increment increment = new Increment(Bytes.toBytes("row1"));
// 对特定列族和列进行增量操作
increment.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("counter"), 1); // 将"counter"列的值增加1
// 执行增量操作
Result result = table.increment(increment);
// 输出增量后的值
long newValue = Bytes.toLong(result.getValue(Bytes.toBytes("C1"), Bytes.toBytes("counter")));
System.out.println("New value of 'counter': " + newValue);
// 关闭表
table.close();
}
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 使用单个API对列进行增量操作,类似于HBase Shell中的incr命令
*/
@Test
public void incrementSingleColumnValue() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 使用incrementColumnValue方法对列进行增量操作
long newValue = table.incrementColumnValue(Bytes.toBytes("row1"), Bytes.toBytes("C1"), Bytes.toBytes("counter"), 5); // 将"counter"列的值增加5
System.out.println("New value of 'counter' after increment: " + newValue);
// 关闭表
table.close();
}
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 获取指定列族和列的计数器值
*/
@Test
public void getCounterByClient() throws IOException {
// 定义表名
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 获取表对象
Table table = connection.getTable(tableName);
// 创建Get对象,指定行键
Get get = new Get(Bytes.toBytes("row1"));
// 获取特定列族和列的计数器值
get.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("counter"));
// 获取数据
Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes("C1"), Bytes.toBytes("counter"));
if (value != null) {
long counterValue = Bytes.toLong(value);
System.out.println("Counter value for row 'row1', column 'C1:counter': " + counterValue);
} else {
System.out.println("Counter for row 'row1' does not exist.");
}
// 使用增量计数器获取最新的值
Increment increment = new Increment(Bytes.toBytes("row1"));
increment.addColumn(Bytes.toBytes("C1"), Bytes.toBytes("counter"), 0);
Result incrementResult = table.increment(increment);
long updatedCounterValue = Bytes.toLong(incrementResult.getValue(Bytes.toBytes("C1"), Bytes.toBytes("counter")));
System.out.println("Updated counter value for row 'row1', column 'C1:counter': " + updatedCounterValue);
// 关闭表
table.close();
}
快照管理
创建快照
快照允许您创建表的时间点副本:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 创建指定表的快照
*/
@Test
public void createSnapshotByClient() throws IOException {
Admin admin = connection.getAdmin();
try {
TableName tableName = TableName.valueOf("CLIENT_TABLE");
String snapshotName = "CLIENT_TABLE_SNAPSHOT";
SnapshotType snapshotType = SnapshotType.FLUSH; // 设置快照类型,支持 FLUSH, SKIPFLUSH, 等
// 创建快照
admin.snapshot(snapshotName, tableName, snapshotType);
System.out.println("Snapshot " + snapshotName + " created successfully for table " + tableName.getNameAsString() + " with type " + snapshotType + ".");
} finally {
admin.close();
}
}
从快照恢复
从快照恢复表也很简单:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 使用快照恢复表,并验证恢复是否成功
*/
@Test
public void restoreSnapshotByClient() throws IOException {
Admin admin = connection.getAdmin();
try {
String snapshotName = "CLIENT_TABLE_SNAPSHOT";
TableName tableName = TableName.valueOf("CLIENT_TABLE");
// 禁用表
if (admin.isTableEnabled(tableName)) {
admin.disableTable(tableName);
}
// 使用快照恢复表
admin.restoreSnapshot(snapshotName);
System.out.println("Table " + tableName.getNameAsString() + " restored successfully from snapshot " + snapshotName + ".");
// 启用表
admin.enableTable(tableName);
// 验证表是否已启用
if (admin.isTableEnabled(tableName)) {
System.out.println("Confirmed: Table " + tableName.getNameAsString() + " is enabled after restore.");
} else {
System.out.println("Warning: Table " + tableName.getNameAsString() + " could not be enabled after restore.");
}
} finally {
admin.close();
}
}
删除快照
删除特定快照或所有快照:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 删除指定的快照
*/
@Test
public void deleteSnapshotByClient() throws IOException {
Admin admin = connection.getAdmin();
try {
String snapshotName = "CLIENT_TABLE_SNAPSHOT";
// 检查快照是否存在
List<SnapshotDescription> snapshots = admin.listSnapshots();
boolean snapshotExists = snapshots.stream().anyMatch(snapshot -> snapshot.getName().equals(snapshotName));
if (snapshotExists) {
// 删除快照
admin.deleteSnapshot(snapshotName);
System.out.println("Snapshot " + snapshotName + " deleted successfully.");
} else {
System.out.println("Snapshot " + snapshotName + " does not exist.");
}
} finally {
admin.close();
}
}
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 删除所有快照
*/
@Test
public void deleteAllSnapshotsByClient() throws IOException {
Admin admin = connection.getAdmin();
try {
// 删除所有快照
Pattern pattern = Pattern.compile(".*");
admin.deleteSnapshots(pattern);
System.out.println("All snapshots deleted successfully.");
} finally {
admin.close();
}
}
列出快照
列出所有快照及其详细信息:
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 列出所有快照以及快照的详细信息
*/
@Test
public void listSnapshotsByClient() throws IOException {
Admin admin = connection.getAdmin();
try {
// 列出所有快照
List<SnapshotDescription> snapshots = admin.listSnapshots();
if (snapshots.isEmpty()) {
System.out.println("No snapshots available.");
} else {
for (SnapshotDescription snapshot : snapshots) {
System.out.println("Snapshot Name: " + snapshot.getName() + ", Table: " + snapshot.getTableName() + ", Creation Time: " + snapshot.getCreationTime() + ", Snapshot Type: " + snapshot.getType());
}
}
} finally {
admin.close();
}
}
克隆快照创建新表、
/**
* @throws IOException 如果操作失败,抛出异常
* @Description 克隆快照创建新表,并验证新表是否成功创建
*/
@Test
public void cloneSnapshotByClient() throws IOException {
Admin admin = connection.getAdmin();
try {
String snapshotName = "CLIENT_TABLE_SNAPSHOT";
TableName newTableName = TableName.valueOf("CLIENT_TABLE_CLONE");
// 克隆快照创建新表
admin.cloneSnapshot(snapshotName, newTableName);
System.out.println("Table " + newTableName.getNameAsString() + " cloned successfully from snapshot " + snapshotName + ".");
// 验证新表是否已创建
if (admin.tableExists(newTableName)) {
System.out.println("Confirmed: Table " + newTableName.getNameAsString() + " exists after cloning.");
} else {
System.out.println("Warning: Table " + newTableName.getNameAsString() + " could not be found after cloning.");
}
} finally {
admin.close();
}
}