写入数据

表格存储提供了PutRowUpdateRow接口用于写入单行数据以及BatchWriteRow接口用于批量写入数据。

说明

组成表的基本单位为行,行由主键和属性组成。其中主键是必须的,且每一行的主键列的名称和类型相同;属性不是必须的,且每一行的属性可以不同。更多信息,请参见宽表模型介绍

插入单行数据

调用PutRow接口新写入一行数据。系统会先删除原行数据(原行的所有列以及所有版本的数据),再写入新行数据。适用于要写入数据较少的场景。

插入单行数据时,您可以根据需要进行如下配置。

  • 系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。您可以自定义数据的版本号。更多信息,请参见数据版本和生命周期

  • 使用条件更新中的行条件或者列条件。更多信息,请参见条件更新

不同的操作返回的结果不同。

  • 如果操作成功,表格存储会返回操作消耗的服务能力单元(CU)。

  • 如果操作发生错误,例如参数检查失败、单行数据量过多、行存在性检查失败等,表格存储会返回错误码。

    说明

    关于错误码的更多信息,请参见错误码参考

更新单行数据

调用UpdateRow接口更新一行数据,可以增加和删除一行中的属性列,删除属性列指定版本的数据,或者更新已存在的属性列的值。如果更新的行不存在,则新增一行数据。适用于更新已写入数据的场景,例如删除属性列、删除某个数据版本、修改属性列值等。

说明

UpdateRow请求中只包含删除指定的列且该行不存在时,则该请求不会新增一行数据。

更新单行数据时,您可以根据需要进行如下配置。

  • 一次请求中支持增加和删除一行中的属性列,删除属性列指定版本的数据,或者更新已存在的属性列的值。

  • 系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。您可以自定义数据的版本号。更多信息,请参见数据版本和生命周期

  • 使用条件更新中的行条件或者列条件。更多信息,请参见条件更新

批量写入数据

调用BatchWriteRow接口在一次请求中进行批量写入操作或者一次对多张表进行写入。适用于要写入、删除或者更新大量数据以及要同时进行增删改数据的场景。

BatchWriteRow操作由多个PutRow、UpdateRow、DeleteRow子操作组成,构造子操作的过程与使用PutRow接口、UpdateRow接口和DeleteRow接口时相同。

BatchWriteRow的各个子操作独立执行,表格存储会分别返回各个子操作的执行结果。

批量写入数据时,您可以根据需要进行如下配置。

  • 一次请求中支持对多张表进行插入、更新或者删除数据操作。

    • 由于批量写入可能存在部分行失败的情况,失败行的Index及错误信息在返回的BatchWriteRowResponse中,但并不抛出异常。因此调用BatchWriteRow接口时,需要检查返回值,可通过BatchWriteRowResponseisAllSucceed方法判断是否全部成功;如果不检查返回值,则可能会忽略掉部分操作的失败。

    • 当服务端检查到某些操作出现参数错误时,BatchWriteRow接口可能会抛出参数错误的异常,此时该请求中所有的操作都未执行。

  • 一次请求中支持分别对PutRow、UpdateRow、DeleteRow子操作设置更新条件。

  • 系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。您可以自定义数据的版本号。更多信息,请参见数据版本和生命周期

  • 使用条件更新中的行条件或者列条件。更多信息,请参见条件更新

使用方式

使用控制台

您可以使用控制台插入单行数据或者更新单行数据。

  1. 登录表格存储控制台

  2. 概览页面,单击实例操作列的实例管理

  3. 实例详情页签的数据表列表区域,单击数据表名称。

  4. 数据管理页签,根据实际插入数据或者更新数据。

    插入单行数据

    1. 单击插入数据

    2. 插入数据对话框,输入主键值。

    3. 单击image图标,并配置属性列名称、属性列类型、属性值以及数据版本号。

      当要增加多个属性列时,请多次单击image图标并配置相应属性信息。

    4. 单击确定

    更新单行数据

    1. 选中要更新的行,单击更新数据

    2. 更新数据对话框,根据需要修改属性列信息。

      如果要增加属性列,请单击image图标,并配置属性信息;如果要删除属性列,请选择操作删除全部;如果要删除特定版本号的数据,请选择操作删除,并选择要删除的数据版本号;如果要更新属性列值,请选择操作更新,并修改属性值。

    3. 单击确定

使用命令行工具CLI

您可以使用命令行工具执行如下命令写入数据。

  • 执行put命令插入单行数据。更多信息,请参见插入新数据

    以下示例用于在数据表中插入一行数据。该行的第一主键列值为"86",第二主键列值为6771,属性列有name(string类型)和country(string类型)两列。

    put --pk '["86", 6771]' --attr '[{"c":"name", "v":"redchen"}, {"c":"country", "v":"china"}]'
  • 执行update命令更新一行数据。更多信息,请参见更新一行数据

    以下示例用于更新第一主键列为"86",第二主键列为6771的行数据。无论此行是否存在均会插入新数据,如果之前行已存在,则写入数据时会覆盖原有数据。

    update --pk '["86", 6771]' --attr '[{"c":"name", "v":"redchen"}, {"c":"country", "v":"china"}]' --condition ignore

使用SDK

您可以使用Java SDKGo SDKPython SDKNode.js SDK.NET SDKPHP SDK写入数据。此处以Java SDK为例介绍数据写入的使用。

插入单行数据

插入数据时,您可以自定义数据版本号、使用列条件或者行条件。

  • 插入数据时由系统自动生成数据版本号

    以下示例用于写入10列属性列,每列写入1个版本,由系统自动生成数据的版本号(时间戳)。

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        //设置数据表名称。
        RowPutChange rowPutChange = new RowPutChange("<TABLE_NAME>", primaryKey);
    
        //加入一些属性列。
        for (int i = 0; i < 10; i++) {
            rowPutChange.addColumn(new Column("Col" + i, ColumnValue.fromLong(i)));
        }
    
        client.putRow(new PutRowRequest(rowPutChange));
    }
                        
  • 插入数据时自定义数据版本号

    以下示例用于写入10列属性列,每列写入3个版本,自定义数据的版本号(时间戳)。

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        //设置数据表名称。
        RowPutChange rowPutChange = new RowPutChange("<TABLE_NAME>", primaryKey);
    
        //加入一些属性列。
        long ts = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 3; j++) {
                rowPutChange.addColumn(new Column("Col" + i, ColumnValue.fromLong(j), ts + j));
            }
        }
    
        client.putRow(new PutRowRequest(rowPutChange));
    }
                        
  • 插入数据时使用行条件

    以下示例用于当原行不存在时,写入10列属性列,每列写入3个版本,自定义数据的版本号(时间戳)。

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        //设置数据表名称。
        RowPutChange rowPutChange = new RowPutChange("<TABLE_NAME>", primaryKey);
    
        //设置条件更新,行条件检查为期望原行不存在。
        rowPutChange.setCondition(new Condition(RowExistenceExpectation.EXPECT_NOT_EXIST));
    
        //加入一些属性列。
        long ts = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 3; j++) {
                rowPutChange.addColumn(new Column("Col" + i, ColumnValue.fromLong(j), ts + j));
            }
        }
    
        client.putRow(new PutRowRequest(rowPutChange));
    }                   
  • 插入数据时使用列条件和行条件

    以下示例用于当原行存在且Col0列的值大于100时,写入10列属性列,每列写入3个版本,自定义数据的版本号(时间戳)。

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        //设置数据表名称。
        RowPutChange rowPutChange = new RowPutChange("<TABLE_NAME>", primaryKey);
    
        //设置条件更新,期望原行存在且Col0列的值大于100时写入数据。
        Condition condition = new Condition(RowExistenceExpectation.EXPECT_EXIST);
        condition.setColumnCondition(new SingleColumnValueCondition("Col0",
                SingleColumnValueCondition.CompareOperator.GREATER_THAN, ColumnValue.fromLong(100)));
        rowPutChange.setCondition(condition);
    
        //加入一些属性列。
        long ts = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 3; j++) {
                rowPutChange.addColumn(new Column("Col" + i, ColumnValue.fromLong(j), ts + j));
            }
        }
    
        client.putRow(new PutRowRequest(rowPutChange));
    }
                        

更新单行数据

更新单行数据时,您可以自定义数据版本号、使用列条件或者行条件。

  • 更新数据时不使用条件

    以下示例用于更新一些列,删除某列的某一版本数据以及删除某列。

    private static void updateRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        //设置数据表名称。
        RowUpdateChange rowUpdateChange = new RowUpdateChange("<TABLE_NAME>", primaryKey);
    
        //更新一些列。
        for (int i = 0; i < 10; i++) {
            rowUpdateChange.put(new Column("Col" + i, ColumnValue.fromLong(i)));
        }
    
        //删除某列的某一版本。
        rowUpdateChange.deleteColumn("Col10", 1465373223000L);
    
        //删除某一列。
        rowUpdateChange.deleteColumns("Col11");
    
        client.updateRow(new UpdateRowRequest(rowUpdateChange));
    }                   
  • 更新数据时使用列条件和行条件

    以下示例用于当原行存在且Col0列的值大于100时更新数据。

    private static void updateRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        //设置数据表名称。
        RowUpdateChange rowUpdateChange = new RowUpdateChange("<TABLE_NAME>", primaryKey);
    
        //设置条件更新,期望原行存在且Col0列的值大于100时更新数据。
        Condition condition = new Condition(RowExistenceExpectation.EXPECT_EXIST);
        condition.setColumnCondition(new SingleColumnValueCondition("Col0",
                SingleColumnValueCondition.CompareOperator.GREATER_THAN, ColumnValue.fromLong(100)));
        rowUpdateChange.setCondition(condition);
    
        //更新一些列。
        for (int i = 0; i < 10; i++) {
            rowUpdateChange.put(new Column("Col" + i, ColumnValue.fromLong(i)));
        }
    
        //删除某列的某一版本。
        rowUpdateChange.deleteColumn("Col10", 1465373223000L);
    
        //删除某一列。
        rowUpdateChange.deleteColumns("Col11");
    
        client.updateRow(new UpdateRowRequest(rowUpdateChange));
    }         

批量写入数据

以下示例中一次BatchWriteRow请求包含2PutRow操作、1DeleteRow操作和1UpdateRow操作用于更新表中数据。

private static void batchWriteRow(SyncClient client) {
    BatchWriteRowRequest batchWriteRowRequest = new BatchWriteRowRequest();

    //构造rowPutChange1。
    PrimaryKeyBuilder pk1Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk1Builder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("pk1"));
    //设置数据表名称。
    RowPutChange rowPutChange1 = new RowPutChange("<TABLE_NAME>", pk1Builder.build());
    //添加一些列。
    for (int i = 0; i < 10; i++) {
        rowPutChange1.addColumn(new Column("Col" + i, ColumnValue.fromLong(i)));
    }
    //添加到batch操作中。
    batchWriteRowRequest.addRowChange(rowPutChange1);

    //构造rowPutChange2。
    PrimaryKeyBuilder pk2Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk2Builder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("pk2"));
    //设置数据表名称。
    RowPutChange rowPutChange2 = new RowPutChange("<TABLE_NAME>", pk2Builder.build());
    //添加一些列。
    for (int i = 0; i < 10; i++) {
        rowPutChange2.addColumn(new Column("Col" + i, ColumnValue.fromLong(i)));
    }
    //添加到batch操作中。
    batchWriteRowRequest.addRowChange(rowPutChange2);

    //构造rowUpdateChange。
    PrimaryKeyBuilder pk3Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk3Builder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("pk3"));
    //设置数据表名称。
    RowUpdateChange rowUpdateChange = new RowUpdateChange("<TABLE_NAME>", pk3Builder.build());
    //添加一些列。
    for (int i = 0; i < 10; i++) {
        rowUpdateChange.put(new Column("Col" + i, ColumnValue.fromLong(i)));
    }
    //删除一列。
    rowUpdateChange.deleteColumns("Col10");
    //添加到batch操作中。
    batchWriteRowRequest.addRowChange(rowUpdateChange);

    //构造rowDeleteChange。
    PrimaryKeyBuilder pk4Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk4Builder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("pk4"));
    //设置数据表名称。
    RowDeleteChange rowDeleteChange = new RowDeleteChange("<TABLE_NAME>", pk4Builder.build());
    //添加到batch操作中。
    batchWriteRowRequest.addRowChange(rowDeleteChange);

    BatchWriteRowResponse response = client.batchWriteRow(batchWriteRowRequest);

    System.out.println("是否全部成功:" + response.isAllSucceed());
    if (!response.isAllSucceed()) {
        for (BatchWriteRowResponse.RowResult rowResult : response.getFailedRows()) {
            System.out.println("失败的行:" + batchWriteRowRequest.getRowChange(rowResult.getTableName(), rowResult.getIndex()).getPrimaryKey());
            System.out.println("失败原因:" + rowResult.getError());
        }
        /**
         * 可以通过createRequestForRetry方法再构造一个请求对失败的行进行重试。此处只给出构造重试请求的部分。
         * 推荐的重试方法是使用SDK的自定义重试策略功能,支持对batch操作的部分行错误进行重试。设置重试策略后,调用接口处无需增加重试代码。
         */
        BatchWriteRowRequest retryRequest = batchWriteRowRequest.createRequestForRetry(response.getFailedRows());
    }
}            

计费说明

表格存储包括VCU模式(原预留模式)和CU模式(原按量模式)两种计费模式。使用不同的计费模式时,计算部分的计费方式不同。

  • VCU模式(原预留模式)

    以包年包月方式预先购买计算能力。计算能力中涵盖数据写的计算消耗。

  • CU模式(原按量模式)

    根据实际计算消耗折算成CU进行计费。同时,根据实例类型不同,计费时需要区分按量读写CU以及预留读写CU。

    说明

    关于实例类型和CU的更多信息,请分别参见实例读写吞吐量

    操作

    CU消耗说明

    PutRow操作

    • 消耗的写CU为修改的行主键数据大小与属性列数据大小之和除以4 KB向上取整。

    • 消耗的读CU与指定的condition情况相关。通过在单行写入请求中设置condition字段,可以指定写入操作执行时是否对行的存在性进行检查。

      • 如果指定条件检查不为IGNORE,则消耗行主键数据大小除以4 KB向上取整的读CU。

      • 如果操作不满足指定的行存在性检查条件,则操作失败并消耗1单位写CU1单位读CU。

    UpdateRow操作

    • 消耗的写CU为修改的行主键数据大小与属性列数据大小之和除以4 KB向上取整。

      操作中包含的需要删除的属性列,只有属性列的列名计入属性列数据大小。

    • 消耗的读CU与指定的condition情况相关。通过在更新单行请求中设置condition字段,可以指定更新操作执行时是否对行的存在性进行检查。

      • 如果指定条件检查不为IGNORE,则消耗行主键数据大小除以4 KB向上取整的读CU。

      • 如果操作不满足指定的行存在性检查条件,则操作失败并消耗1单位写CU1单位读CU。

    BatchWriteRow操作

    按照BatchWriteRow请求中包含的PutRow操作、UpdateRow操作和DeleteRow操作独立计算读写CU。

    其中DeleteRow操作消耗的读CU和写CU说明如下:

    • 消耗的写CU为删除的行主键数据大小除以4 KB向上取整。

    • 如果指定条件检查不为IGNORE,则消耗行主键数据大小除以4 KB向上取整的读CU。

    • 如果操作不满足指定的行存在性检查条件,则操作失败并消耗1单位写CU。