简介:
表格存储(Tablestore)入门指南内容简介了表格存储(Tablestore)是阿里云自研的 NoSQL 多模型数据库,提供海量结构化数据存储以及快速的查询和分析服务。表格存储的分布式存储和强大的索引引擎能够提供 PB 级存储、千万 TPS 以及毫秒级延迟的服务能力。
一、配置开发环境
Tablestore的Java SDK开发环境:
* 开通阿里云表格存储服务:https://www.aliyun.com/product/ots?spm=a2c6h.12873639.article-detail.5.ab432498fb3YeR
* 创建AccessKey(官方教程):https://help.aliyun.com/document_detail/53045.html?spm=a2c6h.12873639.article-detail.6.ab432498fb3YeR
* 配置Java环境(建议:JDK 6及以上版本)
* 使用Maven项目加入依赖项
<dependencies>
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>tablestore</artifactId>
<version>4.12.1</version>
</dependency>
</dependencies>
二、表格的基础操作
0.CreateTable
调用CreateTable接口根据给定的表结构信息创建相应的数据表。
创建数据表(带索引且索引类型为全局二级索引)
private static void createTable(SyncClient client) {
TableMeta tableMeta = new TableMeta(TABLE_NAME);
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY_NAME_1, PrimaryKeyType.STRING)); //为数据表添加主键列。
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY_NAME_2, PrimaryKeyType.INTEGER)); //为数据表添加主键列。
tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_1, DefinedColumnType.STRING)); //为数据表添加预定义列。
tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_2, DefinedColumnType.INTEGER)); //为数据表添加预定义列。
int timeToLive = -1; //数据的过期时间,单位为秒,-1表示永不过期。带索引表的数据表数据生命周期必须设置为-1。
int maxVersions = 1; //保存的最大版本数,1表示每列上最多保存一个版本即保存最新的版本。带索引表的数据表最大版本数必须设置为1。
TableOptions tableOptions = new TableOptions(timeToLive, maxVersions);
ArrayList<IndexMeta> indexMetas = new ArrayList<IndexMeta>();
IndexMeta indexMeta = new IndexMeta(INDEX_NAME);
indexMeta.addPrimaryKeyColumn(DEFINED_COL_NAME_1); //为索引表添加主键列。
indexMeta.addDefinedColumn(DEFINED_COL_NAME_2); //为索引表添加属性列。
indexMetas.add(indexMeta);
CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions, indexMetas); //创建数据表的同时创建索引表。
client.createTable(request);
}
1.GetRow
调用GetRow接口根据指定的主键读取单行数据。
- 如果该行存在,则返回该行的各主键列以及属性列。
- 如果该行不存在,则返回中不包含行,并且不会报错。
private static void getRow(SyncClient client, String pkValue) {
//构造主键。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, PrimaryKeyValue.fromString(pkValue));
PrimaryKey primaryKey = primaryKeyBuilder.build();
//读取一行数据,设置数据表名称。
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(TABLE_NAME, primaryKey);
//设置读取最新版本。
criteria.setMaxVersions(1);
GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
Row row = getRowResponse.getRow();
System.out.println("读取完毕,结果为: ");
System.out.println(row);
//设置读取某些列。
criteria.addColumnsToGet("Col0");
getRowResponse = client.getRow(new GetRowRequest(criteria));
row = getRowResponse.getRow();
System.out.println("读取完毕,结果为:");
System.out.println(row);
}
- 如果请求的行不存在,则消耗1读CU(读服务能力单元)。
- 如果请求的行存在,则消耗读服务能力单元的数值为指定行所有主键列数据大小与实际读取的属性列数据大小之和除以4
KB向上取整。关于数据大小计算的更多信息,请参见产品定价。
2.PutRow
调用PutRow接口插入数据到指定的行。
- 如果指定行不存在,则新增一行;如果指定行存在,则覆盖原有行。
- 返回结果中如果没有出现报错,则表示本次操作成功。
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));
}
- 不设置插入条件时,消耗写服务能力单元的数值为本行的主键数据大小与要插入属性列数据大小之和除以4 KB向上取整。
3.UpdateRow
调用UpdateRow接口更新指定行的数据。
- 如果指定行不存在,则新增一行;如果指定行存在,则根据请求的内容在该行中新增、修改或者删除指定列的值。
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));
}
4.DeleteRow
调用DeleteRow接口删除一行数据。
private static void deleteRow(SyncClient client, String pkValue) {
//构造主键。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, PrimaryKeyValue.fromString(pkValue));
PrimaryKey primaryKey = primaryKeyBuilder.build();
//设置数据表名称。
RowDeleteChange rowDeleteChange = new RowDeleteChange(TABLE_NAME, primaryKey);
client.deleteRow(new DeleteRowRequest(rowDeleteChange));
}
5.GetRange
- 调用GetRange接口读取指定主键范围内的数据。
- 范围读取接口支持按照确定范围进行正序读取和逆序读取,可以设置要读取的行数。如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。
- GetRange操作消耗读服务能力单元的数值为查询范围内所有行主键数据大小与实际读取的属性列数据大小之和除以 4 KB 向上取整。
GetRange操作可能在如下情况停止执行并返回数据。
- 扫描的行数据大小之和达到4 MB。
- 扫描的行数等于5000。
- 返回的行数等于最大返回行数。
- 当前剩余的预留读吞吐量已全部使用,余量不足以读取下一条数据。
private static void getRange(SyncClient client, String startPkValue, String endPkValue) {
RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(TABLE_NAME);
//设置起始主键,以两个主键为例。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME1, PrimaryKeyValue.fromString(startPkValue));//确定值。
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME2, PrimaryKeyValue.INF_MIN);//最小值。
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(primaryKeyBuilder.build());
//设置结束主键。
primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME1, PrimaryKeyValue.fromString(endPkValue));//确定值。
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME2, PrimaryKeyValue.INF_MAX);//最大值。
rangeRowQueryCriteria.setExclusiveEndPrimaryKey(primaryKeyBuilder.build());
rangeRowQueryCriteria.setMaxVersions(1);
System.out.println("GetRange的结果为:");
while (true) {
GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
for (Row row : getRangeResponse.getRows()) {
System.out.println(row);
}
//如果nextStartPrimaryKey不为null,则继续读取。
if (getRangeResponse.getNextStartPrimaryKey() != null) {
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
} else {
break;
}
}
}
6.BatchGetRow
- 调用BatchGetRow接口批量读取一个表或多个表中的若干行数据。
- BatchGetRow操作可视为多个GetRow操作的集合,各个操作独立执行,独立返回结果,独立计算服务能力单元。
- 与执行大量的GetRow操作相比,使用BatchGetRow操作可以有效减少请求的响应时间,提高数据的读取速率。
private static void batchGetRow(SyncClient client) {
MultiRowQueryCriteria multiRowQueryCriteria = new MultiRowQueryCriteria(TABLE_NAME);
//加入10个要读取的行。
for (int i = 0; i < 10; i++) {
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, PrimaryKeyValue.fromString("pk" + i));
PrimaryKey primaryKey = primaryKeyBuilder.build();
multiRowQueryCriteria.addRow(primaryKey);
}
//添加条件。
multiRowQueryCriteria.setMaxVersions(1);
multiRowQueryCriteria.addColumnsToGet("Col0");
multiRowQueryCriteria.addColumnsToGet("Col1");
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter("Col0",
SingleColumnValueFilter.CompareOperator.EQUAL, ColumnValue.fromLong(0));
singleColumnValueFilter.setPassIfMissing(false);
multiRowQueryCriteria.setFilter(singleColumnValueFilter);
BatchGetRowRequest batchGetRowRequest = new BatchGetRowRequest();
//BatchGetRow支持读取多个表的数据,一个multiRowQueryCriteria对应一个表的查询条件,可以添加多个multiRowQueryCriteria。
batchGetRowRequest.addMultiRowQueryCriteria(multiRowQueryCriteria);
BatchGetRowResponse batchGetRowResponse = client.batchGetRow(batchGetRowRequest);
System.out.println("是否全部成功:" + batchGetRowResponse.isAllSucceed());
if (!batchGetRowResponse.isAllSucceed()) {
for (BatchGetRowResponse.RowResult rowResult : batchGetRowResponse.getFailedRows()) {
System.out.println("失败的行:" + batchGetRowRequest.getPrimaryKey(rowResult.getTableName(), rowResult.getIndex()));
System.out.println("失败原因:" + rowResult.getError());
}
/**
* 可以通过createRequestForRetry方法再构造一个请求对失败的行进行重试。此处只给出构造重试请求的部分。
* 推荐的重试方法是使用SDK的自定义重试策略功能,支持对batch操作的部分行错误进行重试。设置重试策略后,调用接口处无需增加重试代码。
*/
BatchGetRowRequest retryRequest = batchGetRowRequest.createRequestForRetry(batchGetRowResponse.getFailedRows());
}
}
7.BatchWriteRow
- 调用BatchWriteRow接口批量插入、修改或删除一个或多个表中的若干行数据。
- BatchWriteRow操作可视为多个PutRow、UpdateRow、DeleteRow操作的集合。各个操作独立执行,独立返回结果,独立计算服务能力单元。
- 与执行大量的单行写操作相比,使用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());
}
}
三、产品计费
1.按量模式
概念
- 计算能力(VCU):1VCU相当于4核16GB的处理能力,表格存储的读写,索引的写入、查询、分析,通道服务均会消耗VCU的计算资源(包年包月)
- 数据存储量(GB):数据存储分高性能存储(ms级别延迟 按小时计费)、容量型村相互(按小时计费)、多元索引存储
- 外网下行流量:上行流量和通过内网访问不收取流量费,仅对外网下行流量收费
计费项:
读吞吐量:每读取4kb数据消耗1读CU(1单位)
写吞吐量:每写入4kb数据消耗1写CU
数据存储量:数据量(GB)*小时*每小时每GB数据存储单价
外网下行流量:下行数据量(GB)*外网下行流量单价
2.付费方式
按量付费,或购买资源包,详情查阅官方文档
附
官方文档路径https://help.aliyun.com/document_detail/27279.html