天天看點

Tablestore入門手冊--資料管理資料管理概覽資料管理使用Tablestore 入門手冊

為了讓表格存儲 Tablestore 使用者更好的了解産品資料管理能力以及SDK使用,本文将結合代碼講述資料管理的功能與使用方式。本文僅講述主表資料的管理使用,并非Tablestore全部的資料管理能力。涉及到二級索引、多元索引查詢能力的内容,将會在以後的文章中單獨介紹。樣例代碼連結位址見: Tablestore-Examples項目

資料管理概覽

Tablestore的資料以PrimaryKey作為唯一行辨別,表資料的管理也是基于PrimaryKey做相應的增、删、改、查。對于Tablestore的主表資料管理,按照操作數量分為:單行操作、批量操作兩類。按照操作類型又分為:寫、讀兩類。單行資料的增、删、改操作都實作了RowChange接口,是以在批量操作中,可以一次請求同時對資料發起增、删、改的操作請求。

Tablestore入門手冊--資料管理資料管理概覽資料管理使用Tablestore 入門手冊

資料管理使用

單行操作

資料插入

資料行級别插入,需要提供完整的PrimaryKey辨別行的唯一ID,然後配置行的屬性值。

注意事項:

  • 主鍵必須完整,并且與表屬性主鍵名、主鍵類型一緻,否側會有參數錯誤;
  • 如果該行資料存在,預設覆寫原資料。如果不想覆寫,可通過設定condition做校驗,若存在則會抛錯。
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
    .build();

RowPutChange rowChange = new RowPutChange(TABLE_NAME, primaryKey);
rowChange.addColumn("string", ColumnValue.fromString("string value"))
    .addColumn("long", ColumnValue.fromLong(1L))
    .addColumn("boolean", ColumnValue.fromBoolean(true))
    .addColumn("double", ColumnValue.fromDouble(1.1))
    .addColumn("binary", ColumnValue.fromBinary(new byte[]{1, 2, 3}));

PutRowRequest putRowRequest = new PutRowRequest(rowChange);

syncClient.putRow(putRowRequest);           

資料插入-條件插入

條件寫入是提供三種行級别條件檢驗,對寫操作都支援,RowChange接口提供的API,主要包含如下行檢驗方式:

  • IGNORE                           // 不做檢查,預設值
  • EXPECT_EXIST                // 期望行存在,存在才會做寫操作
  • EXPECT_NOT_EXIST        // 期望行不存在,不存在才會做寫操作
// 若條件校驗失敗,則會抛錯:OTSConditionCheckFail
rowChange.setCondition(new Condition(RowExistenceExpectation.EXPECT_NOT_EXIST));           

資料插入-自增列

支援自增列資料插入,前提建立表格時相應的主鍵列已設定成自增列。資料插入時,該列主鍵設定為特殊的列值。

PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
    .addPrimaryKeyColumn(PK3, PrimaryKeyValue.AUTO_INCREMENT)    // 自增列的特殊列值
    .build();

RowPutChange rowChange = new RowPutChange(TABLE_NAME_INC, primaryKey);
rowChange.addColumn("string", ColumnValue.fromString("string value"));

rowChange.setReturnType(ReturnType.RT_PK);                         // 擷取主鍵自增列實際插入的值

PutRowRequest putRowRequest = new PutRowRequest(rowChange);

PutRowResponse putRowResponse = syncClient.putRow(putRowRequest);

// 自增列的實際存儲值隻有在傳回的Response中才能拿到
PrimaryKey returnPrimaryKey = putRowResponse.getRow().getPrimaryKey();           

資料删除

基于給定的完整PrimaryKey删除相應行的資料,如果行不存在,删除操作也不會抛錯。

PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
    .build();

RowDeleteChange rowChange = new RowDeleteChange(TABLE_NAME, primaryKey);
DeleteRowRequest getRowRequest = new DeleteRowRequest(rowChange);

syncClient.deleteRow(getRowRequest);           

資料更新

資料更新對指定行做指定字段做更新操作,涵蓋列的增、删、改。

  • 支援條件更新:
    • 支援單列值過濾(SingleColumnValueCondition)
    • 組合多列值過濾(CompositeColumnValueCondition)單列值的與、或、非組合
  • 操作可以是:
    • 删除指定列的指定版本
    • 删除指定列的所有版本
    • 增加新列
    • 更新已存在列
    • 指定列(整數列)做原子加:原子加更新時,如果想要擷取增加後的值,需要設定ReturnType
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
    .build();

RowUpdateChange rowChange = new RowUpdateChange(TABLE_NAME, primaryKey);
rowChange
    .deleteColumns("binary")                                        // 删除指定列所有版本
    .deleteColumn("double", timestamp)                                // 删除指定列指定版本
    .put("string", ColumnValue.fromString("new string value"))        // 更新已存在列
    .put("newCol", ColumnValue.fromString("new col"))                 // 增加新列
    .increment(new Column("long", ColumnValue.fromLong(100L)));        // 原子加
        
rowChange.setReturnType(ReturnType.RT_AFTER_MODIFY);                // 擷取屬性列原子加修改後的值
UpdateRowRequest updateRowRequest = new UpdateRowRequest(rowChange);

UpdateRowResponse updateRowResponse = syncClient.updateRow(updateRowRequest);           

資料更新-條件更新

Tablestore支援行級别的條件更有新,使用者可以提供屬性列值的條件校驗實作條件更新。條件更新也是RowChange接口提供的API。

條件更新支援單列條件校驗、組合屬性列條件校驗兩種,滿足條件時才會完成資料更新,不滿足是會抛錯誤。

單屬性列條件校驗

Condition condition = new Condition(RowExistenceExpectation.EXPECT_EXIST); // 條件更新
condition.setColumnCondition(
        new SingleColumnValueCondition(
                "boolean",
                SingleColumnValueCondition.CompareOperator.EQUAL,
                ColumnValue.fromBoolean(true)));

rowChange.setCondition(condition);           

組合屬性列條件校驗(多列屬性的與、或、非組合)

CompositeColumnValueCondition colCondition = new CompositeColumnValueCondition(CompositeColumnValueCondition.LogicOperator.AND);

ColumnCondition subColCondition1 = new SingleColumnValueCondition(
        "boolean",
        SingleColumnValueCondition.CompareOperator.EQUAL,
        ColumnValue.fromBoolean(true));

ColumnCondition subColCondition2 = new SingleColumnValueCondition(
        "double",
        SingleColumnValueCondition.CompareOperator.GREATER_THAN,
        ColumnValue.fromLong(0L));

colCondition.addCondition(subColCondition1).addCondition(subColCondition2);
Condition condition = new Condition();
condition.setColumnCondition(colCondition);

rowChange.setCondition(condition);           

資料查詢

說明:基于給定的完整PrimaryKey讀取該行行資料。如果資料不存在,則Response.getRow()為空。

  • 預設傳回所有屬性列,如果指定屬性列僅傳回屬性列值;
  • 如果指定屬性列,但該行資料沒有指定的列屬性(有其他屬性列),則會傳回null,不表示該行一定不存在;
  • 多版本表可以通過設定MaxVersion傳回列多個版本的資料;
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
    .build();

SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(TABLE_NAME, primaryKey);
criteria.setMaxVersions(1);

GetRowRequest getRowRequest = new GetRowRequest(criteria);

GetRowResponse getRowResponse = syncClient.getRow(getRowRequest);           

批量操作

資料寫-增删改

批量資料操作與單行操作都是基于RowChange實作的請求建構。是以一個BatchWriteRowRequest中,可以包含增、删、改三種不同的操作。同時,表名參數包含在各自的行資訊中,是以可以實作多表資料的混合寫入操作。使用者可以自己嘗試。

  • 請求失敗,所有的行操作都失敗
  • 請求成功,不表示每一行都成功,需要判斷失敗清單的長度是否為零。對于失敗行,可重新建構請求做重試。
  • 批量寫(增删改)操作建構的請求有限制:行數<=200,總大小<=4M,超過限制會抛錯
BatchWriteRowRequest batchWriteRowRequest = new BatchWriteRowRequest();

/**
 * Multi Put Row
 */
for (long i = 1L; i <= 10L; i++) {
    PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
        .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(i))
        .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
        .build();

    RowPutChange rowChange = new RowPutChange(TABLE_NAME, primaryKey);
    rowChange.addColumn("long", ColumnValue.fromLong(i));

    batchWriteRowRequest.addRowChange(rowChange);
}

/**
 * Multi Update Row
 */
for (long i = 11L; i <= 20L; i++) {
    PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
        .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(i))
        .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
        .build();

    RowUpdateChange rowChange = new RowUpdateChange(TABLE_NAME, primaryKey);
    rowChange.put("long", ColumnValue.fromLong(i));

    batchWriteRowRequest.addRowChange(rowChange);
}

/**
 * Multi Delete Row
 */
for (long i = 21L; i <= 30L; i++) {
    PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
        .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(i))
        .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
        .build();

    RowDeleteChange rowChange = new RowDeleteChange(TABLE_NAME, primaryKey);

    batchWriteRowRequest.addRowChange(rowChange);
}

BatchWriteRowResponse batchWriteRowResponse = syncClient.batchWriteRow(batchWriteRowRequest);
int totalRowCount = batchWriteRowResponse.getRowStatus(TABLE_NAME).size();
int failedRowCount = batchWriteRowResponse.getFailedRows().size();           

批量寫-失敗行重試

批量寫操作成功後,并不表示批請求的所有行操作都成功。行級别的狀态需要單獨判斷。傳回失敗行,對失敗行重新建構BatchWriteRow請求,重新發起請求。

if (batchWriteRowResponse.getFailedRows().size() > 0 ) {
    BatchWriteRowRequest retryRequest = batchWriteRowRequest.createRequestForRetry(
        batchWriteRowResponse.getFailedRows());

    syncClient.batchWriteRow(retryRequest);
}           

多行随機查詢

批量讀查詢支援單表下,批量資料同時讀的能力,使用者建構請求時隻需添加行的完整PrimaryKey即可。

  • 批量讀請求失敗,每一行讀都沒有成功
  • 批量讀請求成功,并不能表示每一行請求都成功,需要判斷失敗清單的長度是否為零。
BatchGetRowRequest batchGetRowRequest = new BatchGetRowRequest();
MultiRowQueryCriteria criteria = new MultiRowQueryCriteria(TABLE_NAME);

for (long i = 1L; i <= 30L; i += 10) {
    PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
        .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(i))
        .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
        .build();

    criteria.addRow(primaryKey);
}

criteria.setMaxVersions(1);
batchGetRowRequest.addMultiRowQueryCriteria(criteria);

BatchGetRowResponse batchGetRowResponse = syncClient.batchGetRow(batchGetRowRequest);
int totalRowCount = batchGetRowResponse.getBatchGetRowResult(TABLE_NAME).size();
int failedRowCount = batchGetRowResponse.getFailedRows().size();           

範圍查詢

表中資料基于PrimaryKey有序排列,表是一個特殊的基于主鍵的聯合索引。是以,資料範圍查詢遵循聯合索引的最左比對原則。即:範圍查詢時如果某一列提供了具體的範圍值(非MIN、MAX),則下一列的範圍限制就被忽略,因為下一列的範圍限制是無效的。具體參考下圖:

Tablestore入門手冊--資料管理資料管理概覽資料管理使用Tablestore 入門手冊
  • 結果與條件不一緻時,請參考最左比對原則
  • 範圍左開右閉,及包含start,但不包含end
  • 正序時,start必須小于end;倒序時:start必須大于end
GetRangeRequest getRangeRequest = new GetRangeRequest();

PrimaryKey start = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(2))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("5"))
    .build();

PrimaryKey end = PrimaryKeyBuilder.createPrimaryKeyBuilder()
    .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(4))
    .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("4"))
    .build();

RangeRowQueryCriteria criteria = new RangeRowQueryCriteria(TABLE_NAME);
criteria.setInclusiveStartPrimaryKey(start);
criteria.setExclusiveEndPrimaryKey(end);
criteria.setDirection(Direction.FORWARD);            // 設定順序
criteria.setMaxVersions(1);                            // 傳回版本個數
criteria.setLimit(20);                                // 每頁傳回行數限制

getRangeRequest.setRangeRowQueryCriteria(criteria);

GetRangeResponse getRangeResponse = syncClient.getRange(getRangeRequest);           

範圍查詢-連續翻頁

當範圍條件資料單次請求未拿到全量資料時,需要使用者基于NextStartPrimaryKey做連續翻頁,進而周遊全部命中資料。如果GetRangeResponse.getNextStartPrimaryKey()非空,則一定還有資料。通過将擷取的PrimaryKey設定到原請求中重新建構,然後再次發起請求。

PrimaryKey nextStartPrimaryKey = null;
do {
    GetRangeResponse getRangeResponse = syncClient.getRange(getRangeRequest);
    List<Row> pageRowList = getRangeResponse.getRows();

    nextStartPrimaryKey = getRangeResponse.getNextStartPrimaryKey();
    if (nextStartPrimaryKey != null) {                 // 判斷存在下一頁,重構請求
        criteria.setInclusiveStartPrimaryKey(nextStartPrimaryKey);
        getRangeRequest.setRangeRowQueryCriteria(criteria);
    }
} while (nextStartPrimaryKey != null);              // 持續翻頁,直到沒有下一頁           

範圍查詢-連續翻頁疊代器

為了友善使用者周遊全量資料,我們提供了疊代器接口。使用者無需關心請求建構、結果判斷等邏輯,隻需将異步Client與請求體作為參數建構GetRangeIterator即可。

  • 疊代器使用的異步Client,可以重制建構也可以通過同步Client轉換;
  • 疊代器内部自動發起請求,消費完一批後自動發起下一批請求;
AsyncClient asyncClient = (AsyncClient) syncClient.asAsyncClient();
GetRangeIterator getRangeIterator = new GetRangeIterator(asyncClient, getRangeRequest);

while (getRangeIterator.hasNext()) {
    Row row = getRangeIterator.next();
}           

Tablestore 入門手冊

本文結合Java SDK的接口調用代碼,介紹了Tablestore在資料管理方面的基本功能與使用方式。代碼已開源在Tablestore-Examples項目中,使用者可以直接運作使用。基于樣例代碼與文章,新使用者能更簡單、更快速地上手Tablestore,歡迎新、老使用者使用與建議。

通過對基礎使用功能的持續輸出,我們将整理出一套完整的入門手冊(含可執行樣例),敬請期待。

專家服務

如有疑問或者需要更好的線上支援,歡迎加入釘釘群:“表格存儲公開交流群”。群内提供免費的線上專家服務,歡迎掃碼加入,群号:23307953

Tablestore入門手冊--資料管理資料管理概覽資料管理使用Tablestore 入門手冊