Tablestore入門手冊-UpdateRow接口詳解

表格存儲Tablestore入門手冊系列主要介紹表格存儲的各個功能接口和適用場景,幫助客戶瞭解和使用表格存儲Tablestore。本文對錶格存儲Tablestore的UpdateRow接口進行介紹,包括其參數、功能示例、使用場景等。

接口概述

UpdateRow接口是表格存儲Tablestore提供的基礎讀寫接口之一,用於對某一行進行更新操作,若指定行不存在,UpdateRow也可以用於新增一行。這裏的更新包括新增、修改或刪除某一列,如果使用了多版本功能,也可以對某列中指定的版本進行新增、修改或刪除。此外,在接口參數中也可以指定條件,僅當滿足條件時進行更新。下面詳細介紹該接口的參數和功能。

接口參數說明

API定義和參數說明

首先是UpdateRow接口的API定義:

message UpdateRowRequest {
    required string table_name = 1;
    required bytes row_change = 2;
    required Condition condition = 3;
    optional ReturnContent return_content = 4; 
}

message UpdateRowResponse {
    required ConsumedCapacity consumed = 1;
    optional bytes row = 2;
}

API定義中的具體參數說明,見官網API文檔:https://help.aliyun.com/document_detail/27307.html

SDK接口和參數說明

在項目代碼中對錶格存儲Tablestore進行讀寫操作,是通過表格存儲Tablestore發佈的各語言SDK進行的,SDK對API進行了封裝,內部自動處理了請求的編碼和響應的解析等。因此對於表格存儲Tablestore的使用者來說,只需要熟悉SDK的接口即可。

下面以Java SDK爲例,介紹SDK中的UpdateRow接口和參數。

接口定義

同步接口(SyncClient):

    /**
     * 更新表中的一行數據。
     * <p>若要更新的行不存在,則新寫入一行數據。</p>
     * <p>更新操作可以包括新寫入一個屬性列或者刪除一個屬性列的一個或多個版本。</p>
     *
     * @param updateRowRequest 執行UpdateRow操作所需的參數。
     * @return TableStore服務返回的結果
     * @throws TableStoreException    TableStore服務返回的異常
     * @throws ClientException 請求的返回結果無效、或遇到網絡異常
     */
    public UpdateRowResponse updateRow(UpdateRowRequest updateRowRequest)
            throws TableStoreException, ClientException;

異步接口(AsyncClient):

    /**
     * 更新表中的一行數據。
     * <p>若要更新的行不存在,則新寫入一行數據。</p>
     * <p>更新操作可以包括新寫入一個屬性列或者刪除一個屬性列的一個或多個版本。</p>
     *
     * @param updateRowRequest 執行UpdateRow操作所需的參數。
     * @param callback 請求完成後調用的回調函數,可以爲null,則代表不需要執行回調函數
     * @return 獲取結果的Future
     * @throws TableStoreException TableStore服務返回的異常
     * @throws ClientException 請求的返回結果無效、或遇到網絡異常
     */
    public Future<UpdateRowResponse> updateRow(
            UpdateRowRequest updateRowRequest, TableStoreCallback<UpdateRowRequest, UpdateRowResponse> callback);

具體參數說明:

變量類型 說明 備註
UpdateRowRequest UpdateRow接口的請求類型,具體內容見後續說明。  
UpdateRowResponse UpdateRow接口的返回結果,具體內容見後續說明。  
TableStoreCallback callback UpdateRow接口的異步回調函數。 僅適用於異步接口。
Future 異步接口的UpdateRow接口返回結果。 僅適用於異步接口。
異步接口調用後不等待請求結束,立即返回future,通過future.get()可以獲取實際接口響應的結果。

UpdateRowRequest參數說明

具體參數說明:

變量類型 說明 備註
TxnRequest(基類) 抽象類,包含TransactionId成員變量,繼承該類的請求類型可用於局部事務中。 TransactionId的使用可參考局部事務的文檔。
UpdateRowRequest UpdateRow接口的請求類型,包含一個成員變量:RowUpdateChange。
繼承自TxnRequest,表示該請求可用於局部事務中。
 
RowUpdateChange 本次更新的具體請求參數。  

RowUpdateChange參數說明

具體參數說明:

變量類型 類說明 成員變量或接口 說明
RowChange(基類) RowUpdateChange的基類,提供了設置表名、主鍵、更新條件、返回類型等通用參數。 tableName 指定本次更新要操作的表名。
    primaryKey 指定本次要更新的行的主鍵。
    condition 指定本次更新操作的條件,可選。
    returnType 枚舉類型,默認爲RT_NONE,表示不返回行的內容,此外還有兩種值:
(1)RT_PK: 返回主鍵,適用於使用主鍵自增列功能的場景,用於返回系統生成的自增主鍵值。
(2)RT_AFTER_MODIFY: 返回修改的列的數據,適用於使用了原子加功能的場景,用於返回原子加之後,某一列的值。此時需要設置returnColumnNames。
    returnColumnNames 當returnType爲RT_AFTER_MODIFY時,指定要返回的被修改的列的列名(適用於原子加的場景)。
RowUpdateChange UpdateRow的具體請求參數,繼承自RowChange類。 put(String columnName, ColumnValue value) 新增或修改某一列的值。
(系統內部會爲該列生成一個新的版本號,單版本模式下無須關心該版本號)
    put(String columnName, ColumnValue value, long version) 新增或修改某一列的某一個版本。
(適用於多版本模式,手動指定版本號寫入)
    put(Column column) 功能同上述put接口,只是參數使用Column類型進行了封裝。
    put(List column) 功能同上述put接口,只是參數爲多列。
    deleteColumns(String columnName) 刪除某列,多版本模式下會刪除該列全部版本。
    deleteColumn(String columnName, long version) 刪除某列的指定版本,適用於多版本模式下對特定版本進行刪除。
    increment(Column column) 對某列進行原子加操作,僅適用於整型類型。
Condition 本次更新的條件。可以指定行存在性條件和列條件,列條件比如“某列的值大於5”。 rowExistenceExpectation 行存在性條件,枚舉類型,有以下三種值:
(1) IGNORE:不對行存在性進行判斷,默認即爲IGNORE。
(2) EXPECT_EXIST: 期望該行存在,若不存在,請求會報錯。
(3) EXPECT_NOT_EXIST:期望該行不存在,若存在,請求會報錯。
注意:
通常情況下,若沒有特殊的設置條件的需求,使用IGNORE即可(保持默認,可不做設置),此時寫入性能也更好。
    columnCondition 列條件,可以設置單列條件(SingleColumnValueCondition),也可以設置多列組合條件(CompositeColumnValueCondition),具體見條件更新的文檔。

UpdateRowResponse參數說明

具體參數說明:

變量類型 成員變量或接口 說明
Response(基類) requestId 本次請求服務端返回的requestId,用於問題調查,建議在出錯時打印到業務日誌中。
  traceId 本次請求SDK生成的traceId,用於問題調查,建議在出錯時打印到業務日誌中。
UpdateRowResponse consumedCapacity 本次請求消耗的讀寫CU,用於計費。
  row 默認情況下爲null,僅當請求中returnType設置爲返回PK(RT_PK)或者某列修改後的值(RT_AFTER_MODIFY)時,返回對應的內容。

功能示例

所有示例代碼可以在Tablestore-Examples項目中查看。

Github地址:https://github.com/aliyun/tablestore-examples/tree/master/basic/Java/DataManage/src/main/java/com/aliyun/tablestore/basic/dataManage

基本更新操作

UpdateRow接口最常用的場景,是對某一行寫入一些列,或者刪除一些列。通常,業務使用單版本表比較多,此時可以忽略列上多版本的概念,按照每列只有一個值來理解。此時UpdateRow就是用於新增、修改或刪除某些列。

新增:若寫入的屬性列之前不存在,UpdateRow執行後會新增該列。
修改:若寫入的屬性列之前已經有值,UpdateRow執行後會修改該列的值。
刪除:UpdateRow可以用於刪除某些列,若該列之前就不存在,則無影響,不會報錯。

示例代碼

下面的代碼執行一次UpdateRow操作,對某一行新增兩列,刪除一列。

    public void updateRowNormally() {
        PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
                .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
                .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
                .build();
        /**
         * 構造RowUpdateChange,設置表名和主鍵
         */
        RowUpdateChange rowChange = new RowUpdateChange(TABLE_NAME, primaryKey);

        /**
         * 寫入兩列
         */
        rowChange.put("col_str", ColumnValue.fromString("value1"));
        rowChange.put("col_long", ColumnValue.fromLong(1));

        /**
         * 刪除某列
         */
        rowChange.deleteColumns("col_to_delete");

        /**
         * 構造UpdateRowRequest
         */
        UpdateRowRequest updateRowRequest = new UpdateRowRequest(rowChange);

        /**
         * 調用updateRow接口。若之前該行不存在,系統會新增該行。
         */
        UpdateRowResponse updateRowResponse = syncClient.updateRow(updateRowRequest);

        /**
         * 打印requestID
         */
        System.out.printf("UpdateRowSuccess, request id: %s\n", updateRowResponse.getRequestId());
    }

使用UpdateRow新增、修改或者刪除某些列,是最基礎的單行數據更新操作,也是很常用的場景。

但在某些場景中,若使用了表格存儲Tablestore的多版本功能,可能會有新增或修改某一列的某個特定版本的需求,或者是需要刪除某一列的某一個版本,此時就需要指定時間戳來更新或刪除,見下面的示例。

指定版本操作

對於設置了保留多版本的表,每一列上都會保留最新的N個版本,UpdateRow可以對其中某個特定版本進行更新,也可以刪除某個特定版本。

示例代碼

下面的代碼執行一次UpdateRow操作,對某一行寫入兩列,指定版本號寫入,同時刪除某列的某個版本,也需要指定要刪除的版本號。

注意:在指定版本號時,需要保證該版本號在表上設置的最大版本偏差內,若超出該偏差範圍,可以調整表上的最大版本偏差設置。

    public void updateRowMultiVersion() {
        PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
                .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
                .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
                .build();
        /**
         * 構造RowUpdateChange,設置表名和主鍵
         */
        RowUpdateChange rowChange = new RowUpdateChange(TABLE_NAME, primaryKey);

        long version = System.currentTimeMillis();

        /**
         * 寫入兩列,指定版本號。
         * 若指定的版本之前不存在,則會新增一個版本;若該版本已存在,會修改該版本的值。
         */
        rowChange.put("col_str", ColumnValue.fromString("value1"), version);
        rowChange.put("col_long", ColumnValue.fromLong(1), version);

        /**
         * 刪除某列的某一個版本,指定版本號。
         */
        rowChange.deleteColumn("col_to_delete", version);

        /**
         * 構造UpdateRowRequest
         */
        UpdateRowRequest updateRowRequest = new UpdateRowRequest(rowChange);

        /**
         * 調用updateRow接口。若之前該行不存在,系統會新增該行。
         */
        UpdateRowResponse updateRowResponse = syncClient.updateRow(updateRowRequest);

        /**
         * 打印requestID
         */
        System.out.printf("UpdateRowSuccess, request id: %s\n", updateRowResponse.getRequestId());
    }

條件更新

UpdateRow接口可以設置更新條件,僅當滿足條件時才進行更新,條件包括行存在性條件和列條件。

行存在性條件:在更新前檢查該行存在或不存在,僅當符合期望時才進行更新操作,否則拋錯。

列條件:目前支持 SingleColumnValueCondition 和 CompositeColumnValueCondition,是基於某一列或者某些列的列值進行條件判斷,比如“col_long的值應該大於5”等。基於列條件,可以使用表格存儲Tablestore實現分佈式的樂觀鎖機制。

條件更新的功能文檔:https://help.aliyun.com/document_detail/35194.html

示例代碼

設置行存在性條件和列條件:

    public void updateRowWithCondition() {
        PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
                .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
                .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
                .build();
        /**
         * 構造RowUpdateChange,設置表名和主鍵
         */
        RowUpdateChange rowChange = new RowUpdateChange(TABLE_NAME, primaryKey);

        /**
         * 設置行存在條件爲期望行存在
         */
        Condition condition = new Condition(RowExistenceExpectation.EXPECT_EXIST);

        /**
         * 設置列條件,若只需要檢查行存在性,可以不設置列條件。
         *
         * 這裏設置列條件爲兩列的組合條件: "(col_boolean == true) && (col_long > 0)"
         */
        CompositeColumnValueCondition colCondition = new CompositeColumnValueCondition(CompositeColumnValueCondition.LogicOperator.AND);
        SingleColumnValueCondition subColCondition1 = new SingleColumnValueCondition(
                "col_boolean",
                SingleColumnValueCondition.CompareOperator.EQUAL,
                ColumnValue.fromBoolean(true));
        subColCondition1.setPassIfMissing(true); // setPassIfMissing(true),表示若該列不存在,也視爲滿足條件。
        SingleColumnValueCondition subColCondition2 = new SingleColumnValueCondition(
                "col_long",
                SingleColumnValueCondition.CompareOperator.GREATER_THAN,
                ColumnValue.fromLong(0L));
        colCondition.addCondition(subColCondition1).addCondition(subColCondition2);
        subColCondition2.setPassIfMissing(false); // setPassIfMissing(false),表示若該列不存在,視爲不滿足條件。

        condition.setColumnCondition(colCondition);
        rowChange.setCondition(condition);

        /**
         * 滿足條件時,寫入兩列
         */
        rowChange.put("col_str", ColumnValue.fromString("value1"));
        rowChange.put("col_long", ColumnValue.fromLong(1));

        /**
         * 構造UpdateRowRequest
         */
        UpdateRowRequest updateRowRequest = new UpdateRowRequest(rowChange);

        /**
         * 調用updateRow接口。
         * 若不滿足設置的條件,比如該行不存在,或者不滿足列條件,會拋OTSException,ErrorCode爲"OTSConditionCheckFail".
         */
        UpdateRowResponse updateRowResponse = syncClient.updateRow(updateRowRequest);

        /**
         * 打印requestID
         */
        System.out.printf("UpdateRowSuccess, request id: %s\n", updateRowResponse.getRequestId());
    }

原子計數器

UpdateRow支持對某一整型列進行原子加操作,原子加操作可以原子的對某一整型列的數據進行增量變更操作,比如在原來的基礎上加10,或者減5,等等。原子加操作可以用來構造原子計數器。

原子計數器的功能文檔:https://help.aliyun.com/document_detail/90949.html

示例代碼

    public void updateRowIncrement() {
        PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
                .addPrimaryKeyColumn(PK1, PrimaryKeyValue.fromLong(1L))
                .addPrimaryKeyColumn(PK2, PrimaryKeyValue.fromString("string"))
                .build();
        /**
         * 構造RowUpdateChange,設置表名和主鍵
         */
        RowUpdateChange rowChange = new RowUpdateChange(TABLE_NAME, primaryKey);

        String columnName = "col_long";
        /**
         * 對col_long這一列進行原子加100操作。
         * 若該列之前不存在,會從0開始累加。
         */
        rowChange.increment(new Column(columnName, ColumnValue.fromLong(100)));

        /**
         * 設置返回修改後的該列值。
         */
        rowChange.setReturnType(ReturnType.RT_AFTER_MODIFY);
        rowChange.addReturnColumn(columnName);

        /**
         * 構造UpdateRowRequest
         */
        UpdateRowRequest updateRowRequest = new UpdateRowRequest(rowChange);

        /**
         * 調用updateRow接口。若之前該行不存在,系統會新增該行。
         */
        UpdateRowResponse updateRowResponse = syncClient.updateRow(updateRowRequest);

        /**
         * 打印修改後的該列的值和RequestId
         */
        System.out.printf("UpdateRowSuccess, column [%s] was updated to %d, request id: %s\n",
                columnName,
                updateRowResponse.getRow().getLatestColumn(columnName).getValue().asLong(),
                updateRowResponse.getRequestId());
    }


原文鏈接
本文爲阿里雲原創內容,未經允許不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章