写入数据

表格存储(Tablestore)提供了单行和批量的方式写入数据到数据表,您可以结合实际场景选择适合的数据写入方式。本文为您介绍如何通过Java SDK写入表格存储数据。

前提条件

写入方式

表格存储提供单行写入、单行更新和批量写入数据功能。不同写入方式的区别和适用场景请参见下表。

写入方式

说明

适用场景

写入单行数据

调用 PutRow 接口新写入一行数据。

适用于写入少量数据的场景。

更新单行数据

调用 UpdateRow 接口更新一行数据。

适用于更新少量数据的场景。

批量写入数据

调用 BatchWriteRow 接口在一次请求中进行批量写入操作或者一次对多张表进行写入。

适用于增删改大量数据或者同时需要进行数据增删改操作的场景。

参数说明

数据写入的相关参数说明如下表所示。

参数

说明

tableName

数据表的名称。

primaryKey

数据表的主键信息。包括主键列名、主键类型和主键值。

重要
  • 设置的主键个数和类型必须与数据表的主键个数和类型保持一致。

  • 主键为自增列时,只需将自增列的值设置为占位符。具体方式,请参见主键列自增

column

属性列信息。包括属性列名称、属性列的值、属性列数据类型(可选)和时间戳(可选)。

  • 属性列名称。由英文字符(a~z)或(A~Z)、数字(0~9)和下划线(_)组成,首字母不能为数字,大小写敏感,长度在1~255个字符之间。

  • 属性列数据类型。支持字符串、整型、二进制、浮点数和布尔值。

  • 时间戳即数据的版本号。默认由系统自动生成,也可以自行指定。更多关于版本号的信息,请参见数据版本和生命周期

说明
  • 删除属性列时,只需要设置属性列名称。

  • 删除属性列特定版本的数据时,需要设置属性列名称和时间戳。

  • 删除一行数据的全部属性列不等于删除该行。如果需要删除该行,请使用DeleteRow接口操作,具体操作请参见删除数据

condition

写入条件。包括行存在性条件和列判断条件,更多信息,请参见条件更新

写入单行数据

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

说明

本文示例中的pkValue均表示主键列值,使用时请根据实际填写具体数据。写入数据时,您需要指定完整的主键以及需要写入的属性列信息。您也可以根据需要配置数据写入条件,例如设置只有在行不存在时才写入数据。

以下示例代码为您展示如何使用系统自动生成的数据版本号、自定义数据版本号以及如何使用写入条件。

写入数据时系统自动生成数据版本号

以下示例代码新增了一行数据,写入10个属性列,每列写入1个版本,由系统自动生成数据的版本号(时间戳)。

private static void putRow(SyncClient client, String pkValue) {
    //构造主键。
    PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    primaryKeyBuilder.addPrimaryKeyColumn("your_primaryKey", PrimaryKeyValue.fromString(pkValue));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    //设置数据表名称。
    RowPutChange rowPutChange = new RowPutChange("your_tableName", 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("your_primaryKey", PrimaryKeyValue.fromString(pkValue));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    //设置数据表名称。
    RowPutChange rowPutChange = new RowPutChange("your_tableName", 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("your_primaryKey", PrimaryKeyValue.fromString(pkValue));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    //设置数据表名称。
    RowPutChange rowPutChange = new RowPutChange("your_tableName", 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("your_primaryKey", PrimaryKeyValue.fromString(pkValue));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    //设置数据表名称。
    RowPutChange rowPutChange = new RowPutChange("your_tableName", 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接口更新一行数据。可以更新属性列的值、增加和删除属性列、删除属性列指定版本的数据。如果更新的行不存在,则新增一行数据。

说明

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

以下示例代码均更新了一些列、删除Col1列的某一数据版本,并删除了Col0列,区别在于是否使用了写入条件。

更新数据时不使用条件

以下示例代码在更新数据时不使用写入条件。

private static void updateRow(SyncClient client, String pkValue) {
    //构造主键。
    PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    primaryKeyBuilder.addPrimaryKeyColumn("your_primaryKey", PrimaryKeyValue.fromString(pkValue));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    //设置数据表名称。
    RowUpdateChange rowUpdateChange = new RowUpdateChange("your_tableName", primaryKey);

    //更新一些列。
    for (int i = 0; i < 10; i++) {
        rowUpdateChange.put(new Column("Col" + i, ColumnValue.fromLong(i)));
    }

    //删除某列的某一版本。
    rowUpdateChange.deleteColumn("Col1", 1465373223000L);

    //删除某一列。
    rowUpdateChange.deleteColumns("Col0");

    client.updateRow(new UpdateRowRequest(rowUpdateChange));
}

更新数据时使用列和行条件

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

private static void updateRow(SyncClient client, String pkValue) {
    //构造主键。
    PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    primaryKeyBuilder.addPrimaryKeyColumn("your_primaryKey", PrimaryKeyValue.fromString(pkValue));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    //设置数据表名称。
    RowUpdateChange rowUpdateChange = new RowUpdateChange("your_tableName", 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("Col1", 1465373223000L);

    //删除某一列。
    rowUpdateChange.deleteColumns("Col0");

    client.updateRow(new UpdateRowRequest(rowUpdateChange));
}

批量写入数据

调用BatchWriteRow接口在一次请求中进行批量写入操作或者一次对多张表进行写入。

BatchWriteRow操作由多个PutRow、UpdateRowDeleteRow子操作组成,构造子操作的过程与单独使用PutRow接口、UpdateRow接口和DeleteRow接口相同。各个子操作独立执行,表格存储会分别返回每个子操作的执行结果。

说明
  • 服务端检查到部分操作的参数错误时,BatchWriteRow接口会抛出参数错误异常,此时该请求中的所有操作都将不执行。

  • 批量写入过程中可能存在部分行写入失败的情况,请求返回的BatchWriteRowResponse包含了失败行的Index及错误信息。建议您检查返回值,可以通过BatchWriteRowResponseisAllSucceed方法判断批量写入是否全部成功。

以下示例代码的BatchWriteRow请求中包含2PutRow操作、1UpdateRow操作和1DeleteRow操作。

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

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

    //构造第2个rowPutChange。
    PrimaryKeyBuilder pk2Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk2Builder.addPrimaryKeyColumn("your_primaryKey", PrimaryKeyValue.fromString("pkValue2"));
    //设置数据表名称。
    RowPutChange rowPutChange2 = new RowPutChange("your_tableName", 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("your_primaryKey", PrimaryKeyValue.fromString("pkValue3"));
    //设置数据表名称。
    RowUpdateChange rowUpdateChange = new RowUpdateChange("your_tableName", pk3Builder.build());
    //添加一些列。
    for (int i = 0; i < 10; i++) {
        rowUpdateChange.put(new Column("Col" + i, ColumnValue.fromLong(i)));
    }
    //删除一列。
    rowUpdateChange.deleteColumns("Col0");
    //添加到batch操作中。
    batchWriteRowRequest.addRowChange(rowUpdateChange);

    //构造rowDeleteChange。
    PrimaryKeyBuilder pk4Builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pk4Builder.addPrimaryKeyColumn("your_primaryKey", PrimaryKeyValue.fromString("pkValue4"));
    //设置数据表名称。
    RowDeleteChange rowDeleteChange = new RowDeleteChange("your_tableName", 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());
    }
}

常见问题

相关文档

  • 如果您想了解更多表格存储数据操作的示例代码,请参见GitHub示例代码

  • BatchWriteRow接口单次只能写入200行数据,如果您需要高并发数据写入,请使用TableStoreWriter工具。更多信息,请参见使用TableStoreWriter并发写入数据

  • 如果您需要为在线应用提供实时统计功能,例如统计帖子的PV(页面浏览量)等,可以通过原子计数器实现。更多信息,请参见原子计数器

  • 如果您需要进行单行写或多行写的原子操作,可以通过局部事务实现。更多信息,请参见局部事务

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