表格存储(Tablestore)提供了单行和批量的方式写入数据到数据表,您可以结合实际场景选择适合的数据写入方式。本文为您介绍如何通过Java SDK写入表格存储数据。
前提条件
初始化OTSClient。具体操作,请参见初始化OTSClient。
在表格存储的实例中创建数据表。
写入方式
表格存储提供单行写入、单行更新和批量写入数据功能。不同写入方式的区别和适用场景请参见下表。
写入方式 | 说明 | 适用场景 |
调用 PutRow 接口新写入一行数据。 | 适用于写入少量数据的场景。 | |
调用 UpdateRow 接口更新一行数据。 | 适用于更新少量数据的场景。 | |
调用 BatchWriteRow 接口在一次请求中进行批量写入操作或者一次对多张表进行写入。 | 适用于增删改大量数据或者同时需要进行数据增删改操作的场景。 |
参数说明
数据写入的相关参数说明如下表所示。
参数 | 说明 |
tableName | 数据表的名称。 |
primaryKey | 数据表的主键信息。包括主键列名、主键类型和主键值。 重要
|
column | 属性列信息。包括属性列名称、属性列的值、属性列数据类型(可选)和时间戳(可选)。
说明
|
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、UpdateRow或DeleteRow子操作组成,构造子操作的过程与单独使用PutRow接口、UpdateRow接口和DeleteRow接口相同。各个子操作独立执行,表格存储会分别返回每个子操作的执行结果。
服务端检查到部分操作的参数错误时,BatchWriteRow接口会抛出参数错误异常,此时该请求中的所有操作都将不执行。
批量写入过程中可能存在部分行写入失败的情况,请求返回的BatchWriteRowResponse包含了失败行的Index及错误信息。建议您检查返回值,可以通过BatchWriteRowResponse的
isAllSucceed
方法判断批量写入是否全部成功。
以下示例代码的BatchWriteRow请求中包含2个PutRow操作、1个UpdateRow操作和1个DeleteRow操作。
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入门与实战。