表格存储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 | UpdateRow接口的请求类型,具体内容见后续说明。 | |
UpdateRowResponse | UpdateRow接口的返回结果,具体内容见后续说明。 | |
TableStoreCallback callback | UpdateRow接口的异步回调函数。 | 仅适用于异步接口。 |
Future | 异步接口的UpdateRow接口返回结果。 | 仅适用于异步接口。 异步接口调用后不等待请求结束,立即返回future,通过future.get()可以获取实际接口响应的结果。 |
UpdateRowRequest参数说明
具体参数说明:
变量类型 | 说明 | 备注 |
---|---|---|
TxnRequest(基类) | 抽象类,包含TransactionId成员变量,继承该类的请求类型可用于局部事务中。 | TransactionId的使用可参考局部事务的文档。 |
UpdateRowRequest | UpdateRow接口的请求类型,包含一个成员变量:RowUpdateChange。 继承自TxnRequest,表示该请求可用于局部事务中。 |
|
RowUpdateChange | 本次更新的具体请求参数。 |
RowUpdateChange参数说明
具体参数说明:
变量类型 | 类说明 | 成员变量或接口 | 说明 |
---|---|---|---|
RowChange(基类) | RowUpdateChange的基类,提供了设置表名、主键、更新条件、返回类型等通用参数。 | tableName | 指定本次更新要操作的表名。 |
primaryKey | 指定本次要更新的行的主键。 | ||
condition | 指定本次更新操作的条件,可选。 | ||
returnType | 枚举类型,默认为RT_NONE,表示不返回行的内容,此外还有两种值: (1)RT_PK: 返回主键,适用于使用主键自增列功能的场景,用于返回系统生成的自增主键值。 (2)RT_AFTER_MODIFY: 返回修改的列的数据,适用于使用了原子加功能的场景,用于返回原子加之后,某一列的值。此时需要设置returnColumnNames。 |
||
returnColumnNames | 当returnType为RT_AFTER_MODIFY时,指定要返回的被修改的列的列名(适用于原子加的场景)。 | ||
RowUpdateChange | UpdateRow的具体请求参数,继承自RowChange类。 | put(String columnName, ColumnValue value) | 新增或修改某一列的值。 (系统内部会为该列生成一个新的版本号,单版本模式下无须关心该版本号) |
put(String columnName, ColumnValue value, long version) | 新增或修改某一列的某一个版本。 (适用于多版本模式,手动指定版本号写入) |
||
put(Column column) | 功能同上述put接口,只是参数使用Column类型进行了封装。 | ||
put(List column) | 功能同上述put接口,只是参数为多列。 | ||
deleteColumns(String columnName) | 删除某列,多版本模式下会删除该列全部版本。 | ||
deleteColumn(String columnName, long version) | 删除某列的指定版本,适用于多版本模式下对特定版本进行删除。 | ||
increment(Column column) | 对某列进行原子加操作,仅适用于整型类型。 | ||
Condition | 本次更新的条件。可以指定行存在性条件和列条件,列条件比如“某列的值大于5”。 | rowExistenceExpectation | 行存在性条件,枚举类型,有以下三种值: (1) IGNORE:不对行存在性进行判断,默认即为IGNORE。 (2) EXPECT_EXIST: 期望该行存在,若不存在,请求会报错。 (3) EXPECT_NOT_EXIST:期望该行不存在,若存在,请求会报错。 注意: 通常情况下,若没有特殊的设置条件的需求,使用IGNORE即可(保持默认,可不做设置),此时写入性能也更好。 |
columnCondition | 列条件,可以设置单列条件(SingleColumnValueCondition),也可以设置多列组合条件(CompositeColumnValueCondition),具体见条件更新的文档。 |
UpdateRowResponse参数说明
具体参数说明:
变量类型 | 成员变量或接口 | 说明 |
---|---|---|
Response(基类) | requestId | 本次请求服务端返回的requestId,用于问题调查,建议在出错时打印到业务日志中。 |
traceId | 本次请求SDK生成的traceId,用于问题调查,建议在出错时打印到业务日志中。 | |
UpdateRowResponse | consumedCapacity | 本次请求消耗的读写CU,用于计费。 |
row | 默认情况下为null,仅当请求中returnType设置为返回PK(RT_PK)或者某列修改后的值(RT_AFTER_MODIFY)时,返回对应的内容。 |
功能示例
所有示例代码可以在Tablestore-Examples项目中查看。
基本更新操作
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());
}
专家服务
如有疑问或者需要更好的在线支持,欢迎加入钉钉群:“表格存储公开交流群”。群内提供免费的在线专家服务,欢迎扫码加入,群号:23307953