1

表格存储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参数说明

具体参数说明:

RowUpdateChange参数说明

具体参数说明:

UpdateRowResponse参数说明

具体参数说明:

功能示例

所有示例代码可以在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操作,对某一行写入两列,指定版本号写入,同时删除某列的某个版本,也需要指定要删除的版本号。

注意:在指定版本号时,需要保证该版本号在表上设置的最大版本偏差内,若超出该偏差范围,可以调整表上的最大版本偏差设置(见文档:https://help.aliyun.com/document_detail/89939.html)。

    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());
    }

本文作者:亦征

阅读原文

本文为阿里云内容,未经允许不得转载。


阿里云云栖号
27.8k 声望35.7k 粉丝

阿里云官网内容平台