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

如果需要了解表格存储各场景的应用案例,请参见快速玩转Tablestore入门与实战

说明 本文示例中的pkValue均表示主键列值,使用时请根据实际填写具体数据。

前提条件

  • 已初始化OTSClient。具体操作,请参见初始化
  • 已创建数据表并写入数据。

插入单行数据

调用PutRow接口新写入一行数据。如果该行已存在,则先删除原行数据(原行的所有列以及所有版本的数据),再写入新行数据。

参数

参数 说明
tableName 数据表名称。
primaryKey 行的主键。
说明
  • 设置的主键个数和类型必须和数据表的主键个数和类型一致。
  • 当主键为自增列时,只需将自增列的值设置为占位符。更多信息,请参见主键列自增
condition 使用条件更新,可以设置原行的存在性条件或者原行中某列的列值条件。更多信息,请参见条件更新
说明
  • RowExistenceExpectation.IGNORE表示无论此行是否存在均会插入新数据,如果之前行已存在,则写入数据时会覆盖原有数据。
  • RowExistenceExpectation.EXPECT_EXIST表示只有此行存在时才会插入新数据,写入数据时会覆盖原有数据。
  • RowExistenceExpectation.EXPECT_NOT_EXIST表示只有此行不存在时才会插入数据。
column 行的属性列。
  • 每一项的顺序是属性名、属性值ColumnValue、属性类型ColumnType(可选)、时间戳(可选)。
  • ColumnType可以是INTEGER、STRING(UTF-8编码字符串)、BINARY、BOOLEAN、DOUBLE五种,分别用ColumnType.INTEGER、ColumnType.STRING、ColumnType.BINARY、ColumnType.BOOLEAN、ColumnType.DOUBLE表示,其中BINARY不可省略,其他类型都可以省略。
  • 时间戳即数据的版本号。更多信息,请参见数据版本和生命周期

    数据的版本号可以由系统自动生成或者自定义,如果不设置此参数,则默认由系统自动生成。

    • 当由系统自动生成数据的版本号时,系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。
    • 当自定义数据的版本号时,版本号需要为64位的毫秒单位时间戳且在有效版本范围内。

示例

  • 示例1

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

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, 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));
    }
                        
  • 示例2

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

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, 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));
    }
                        
  • 示例3

    期望原行不存在时,写入10列属性列,每列写入3个版本,自定义数据的版本号(时间戳)。

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, 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));
    }
                        
  • 示例4

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

    private static void putRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, 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));
    }
                        

更新单行数据

调用UpdateRow接口更新一行数据,可以增加和删除一行中的属性列,删除属性列指定版本的数据,或者更新已存在的属性列的值。如果更新的行不存在,则新增一行数据。
说明 当UpdateRow请求中只包含删除指定的列且该行不存在时,则该请求不会新增一行数据。

参数

参数 说明
tableName 数据表名称。
primaryKey 行的主键。
说明 设置的主键个数和类型必须和数据表的主键个数和类型一致。
condition 使用条件更新,可以设置原行的存在性条件或者原行中某列的列值条件。更多信息,请参见条件更新
column 更新的属性列。
  • 增加或更新数据时,需要设置属性名、属性值、属性类型(可选)、时间戳(可选)。

    时间戳即数据的版本号,可以由系统自动生成或者自定义,如果不设置此参数,则默认由系统自动生成。更多信息,请参见数据版本和生命周期

    • 当由系统自动生成数据的版本号时,系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。
    • 当自定义数据的版本号时,版本号需要为64位的毫秒单位时间戳且在有效版本范围内。
  • 删除属性列特定版本的数据时,只需要设置属性名和时间戳。

    时间戳是64位整数,单位为毫秒,表示某个特定版本的数据。

  • 删除属性列时,只需要设置属性名。
    说明 删除一行的全部属性列不等同于删除该行,如果需要删除该行,请使用DeleteRow操作。

示例

  • 示例1

    更新一些列,删除某列的某一版本数据,删除某列。

    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));
    }                   
  • 示例2

    设置更新的条件。

    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接口在一次请求中进行批量的写入操作,也支持一次对多张表进行写入。BatchWriteRow操作由多个PutRow、UpdateRow、DeleteRow子操作组成,构造子操作的过程与使用PutRow接口、UpdateRow接口和DeleteRow接口时相同,也支持使用条件更新。

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

注意事项

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

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

示例

一次BatchWriteRow请求包含2个PutRow操作、1个UpdateRow操作和1个DeleteRow操作。

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

    //构造rowPutChange1。
    PrimaryKeyBuilder pk1Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk1Builder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, 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(PRIMARY_KEY_NAME, 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(PRIMARY_KEY_NAME, 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(PRIMARY_KEY_NAME, 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());
    }
}            

详细代码请参见BatchWriteRow@GitHub