您可以使用 AWS Management Console、AWS Command Line Interface (AWS CLI) 或 DynamoDB API 访问 Amazon DynamoDB。
本文着重说一下,AWS CLI终端命令行操作DynamoDB。
参考:AWS CLI
以MAC OS举例说明:
如果您有sudo权限,您可以为计算机上的所有用户安装 AWS CLI。我们在一个易于复制和粘贴的组中提供了这些步骤。请参阅以下步骤中每行的说明。
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg ./AWSCLIV2.pkg -target /
which aws
aws --version
输出显示:
aws-cli/2.4.5 Python/3.8.8 Darwin/18.7.0 botocore/2.4.5
配置本机和AWS
aws configure
# 按照配置填写自己AK和SK以及region
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json
以下 AWS CLI 示例使用 create-table 创建一个新的 Music 表。
aws dynamodb create-table \
--table-name Music \
--attribute-definitions \
AttributeName=Artist,AttributeType=S \
AttributeName=SongTitle,AttributeType=S \
--key-schema \
AttributeName=Artist,KeyType=HASH \
AttributeName=SongTitle,KeyType=RANGE \
--provisioned-throughput \
ReadCapacityUnits=5,WriteCapacityUnits=5 \
--table-class STANDARD
使用 create-table 返回以下示例结果。
{
"TableDescription": {
"TableArn": "arn:aws:dynamodb:us-west-2:522194210714:table/Music",
"AttributeDefinitions": [
{
"AttributeName": "Artist",
"AttributeType": "S"
},
{
"AttributeName": "SongTitle",
"AttributeType": "S"
}
],
"ProvisionedThroughput": {
"NumberOfDecreasesToday": 0,
"WriteCapacityUnits": 5,
"ReadCapacityUnits": 5
},
"TableClassSummary": {
"LastUpdateDateTime": 1558028402.69,
"TableClass": "STANDARD"
},
"TableSizeBytes": 0,
"TableName": "Music",
"TableStatus": "CREATING",
"TableId": "d04c7240-0e46-435d-b231-d54091fe1017",
"KeySchema": [
{
"KeyType": "HASH",
"AttributeName": "Artist"
},
{
"KeyType": "RANGE",
"AttributeName": "SongTitle"
}
],
"ItemCount": 0,
"CreationDateTime": 1558028402.69
}
}
请注意,TableStatus 字段的值设置为 CREATING。
要验证 DynamoDB 是否已完成创建 Music 表,请使用 describe-table 命令。
aws dynamodb describe-table --table-name Music | grep TableStatus
此命令将返回以下结果。在 DynamoDB 创建完表后,TableStatus 字段的值将设置为 ACTIVE。
aws dynamodb put-item \
--table-name Music \
--item \
'{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "1"}}'
aws dynamodb put-item \
--table-name Music \
--item \
'{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Howdy"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "2"}}'
aws dynamodb execute-statement --statement "INSERT INTO Music \
VALUE \
{'Artist':'No One You Know','SongTitle':'Call Me Today', 'AlbumTitle':'Somewhat Famous', 'Awards':'1'}"
aws dynamodb execute-statement --statement "INSERT INTO Music \
VALUE \
{'Artist':'No One You Know','SongTitle':'Howdy', 'AlbumTitle':'Somewhat Famous', 'Awards':'2'}"
DynamoDB API方式读取数据
注意
DynamoDB 的默认行为是最终一致性读取。下面用 consistent-read 参数演示较强的一致性读取。
aws dynamodb get-item --consistent-read \
--table-name Music \
--key '{ "Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}}'
使用 get-item 返回以下示例结果。
{
"Item": {
"AlbumTitle": {
"S": "Songs About Life"
},
"Awards": {
"N": "10"
},
"SongTitle": {
"S": "Happy Day"
},
"Artist": {
"S": "Acme Band"
}
}
}
PartiQL for DynamoDB
aws dynamodb execute-statement --statement "SELECT * FROM Music \
WHERE Artist='Acme Band' AND SongTitle='Happy Day'"
使用 PartiQL Select 语句返回以下示例结果。
{
"Items": [
{
"AlbumTitle": {
"S": "Songs About Life"
},
"Awards": {
"S": "10"
},
"Artist": {
"S": "Acme Band"
},
"SongTitle": {
"S": "Happy Day"
}
}
]
}
}
下面的 AWS CLI 示例使用 delete-table 删除 Music 表。
aws dynamodb delete-table --table-name Music
AWS DynamoDB SDK pom依赖如下
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdkgroupId>
<artifactId>bomartifactId>
<version>2.17.230version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdkgroupId>
<artifactId>dynamodb-enhancedartifactId>
<version>2.17.123version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.13.1version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.1version>
dependency>
<dependency>
<groupId>software.amazon.awssdkgroupId>
<artifactId>kmsartifactId>
dependency>
<dependency>
<groupId>software.amazon.awssdkgroupId>
<artifactId>dynamodbartifactId>
dependency>
dependencies>
public static String createTable(DynamoDbClient ddb, String tableName, String key) {
DynamoDbWaiter dbWaiter = ddb.waiter();
CreateTableRequest request = CreateTableRequest.builder()
.attributeDefinitions(AttributeDefinition.builder()
.attributeName(key)
.attributeType(ScalarAttributeType.S)
.build())
.keySchema(KeySchemaElement.builder()
.attributeName(key)
.keyType(KeyType.HASH)
.build())
.provisionedThroughput(ProvisionedThroughput.builder()
.readCapacityUnits(new Long(10))
.writeCapacityUnits(new Long(10))
.build())
.tableName(tableName)
.build();
String newTable ="";
try {
CreateTableResponse response = ddb.createTable(request);
DescribeTableRequest tableRequest = DescribeTableRequest.builder()
.tableName(tableName)
.build();
// Wait until the Amazon DynamoDB table is created.
WaiterResponse<DescribeTableResponse> waiterResponse = dbWaiter.waitUntilTableExists(tableRequest);
waiterResponse.matched().response().ifPresent(System.out::println);
newTable = response.tableDescription().tableName();
return newTable;
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
return "";
}
调用如下:
public static void main1(String[] args) {
String tableName = "Customer";
String key = "id";
System.out.println("Creating an Amazon DynamoDB table "+tableName +" with a simple primary key: " +key );
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_WEST_2;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
String result = createTable(ddb, tableName, key);
System.out.println("New table is "+result);
ddb.close();
}
使用增强型客户端将项目放入表中。
public static void putRecord(DynamoDbEnhancedClient enhancedClient) {
try {
DynamoDbTable<Customer> custTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
// Create an Instant value.
LocalDate localDate = LocalDate.parse("2020-04-07");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
// Populate the Table.
Customer custRecord = new Customer();
custRecord.setCustName("Tom red");
custRecord.setId("id119");
custRecord.setEmail("tred@noserver.com");
custRecord.setRegistrationDate(instant) ;
// Put the customer data into an Amazon DynamoDB table.
custTable.putItem(custRecord);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
System.out.println("Customer data added to the table.");
}
测试如下:
public static void main2(String[] args) {
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_WEST_2;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
putRecord(enhancedClient) ;
ddb.close();
}
public static int queryTable(DynamoDbClient ddb,
String tableName,
String partitionKeyName,
String partitionKeyVal,
String partitionAlias) {
// Set up an alias for the partition key name in case it's a reserved word.
HashMap<String,String> attrNameAlias = new HashMap<String,String>();
attrNameAlias.put(partitionAlias, partitionKeyName);
// Set up mapping of the partition name with the value.
HashMap<String, AttributeValue> attrValues = new HashMap<>();
attrValues.put(":"+partitionKeyName, AttributeValue.builder()
.s(partitionKeyVal)
.build());
QueryRequest queryReq = QueryRequest.builder()
.tableName(tableName)
.keyConditionExpression(partitionAlias + " = :" + partitionKeyName)
.expressionAttributeNames(attrNameAlias)
.expressionAttributeValues(attrValues)
.build();
try {
QueryResponse response = ddb.query(queryReq);
return response.count();
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
return -1;
}
测试如下:
public static void main(String[] args) {
String tableName = "Music";
String partitionKeyName = "Artist";
String partitionKeyVal = "No One You Know";
// For more information about an alias, see:
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html
String partitionAlias = "#a";
System.out.format("Querying %s", tableName);
System.out.println("");
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_WEST_2;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
int count = queryTable(ddb, tableName, partitionKeyName, partitionKeyVal,partitionAlias ) ;
System.out.println("There were "+count + " record(s) returned");
ddb.close();
}
public static String modifyItem(DynamoDbEnhancedClient enhancedClient, String keyVal, String email) {
try {
DynamoDbTable<Customer> mappedTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
Key key = Key.builder()
.partitionValue(keyVal)
.build();
// Get the item by using the key and update the email value.
Customer customerRec = mappedTable.getItem(r->r.key(key));
customerRec.setEmail(email);
mappedTable.updateItem(customerRec);
return customerRec.getEmail();
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
return "";
}
测试如下:
public static void main3(String[] args) {
String key = "id119";
String email = "liyang19900109@gmail.com";
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_WEST_2;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
String updatedValue = modifyItem(enhancedClient,key,email);
System.out.println("The updated name value is "+updatedValue);
ddb.close();
}
public static void deleteDymamoDBItem(DynamoDbClient ddb, String tableName, String key, String keyVal) {
HashMap<String,AttributeValue> keyToGet = new HashMap<>();
keyToGet.put(key, AttributeValue.builder()
.s(keyVal)
.build());
DeleteItemRequest deleteReq = DeleteItemRequest.builder()
.tableName(tableName)
.key(keyToGet)
.build();
try {
ddb.deleteItem(deleteReq);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
测试:
public static void main4(String[] args) {
String tableName = "Customer";
String key = "id";
String keyVal = "id119";
System.out.format("Deleting item \"%s\" from %s\n", keyVal, tableName);
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_WEST_2;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
deleteDymamoDBItem(ddb, tableName, key, keyVal);
ddb.close();
}
概述了使用 AWS SDK 编程 Amazon DynamoDB 应用程序。
每个 AWS SDK 提供了一个或多个用于使用 Amazon DynamoDB 的编程接口。这些接口范围从简单的低级 DynamoDB 包装到面向对象的持久层。可用接口因您使用的 AWS SDK 和编程语言而不同。
Low-Level-Interface 类似于 jdbc
High-Level-Interface 类似于mybatis
每个语言特定 AWS SDK 为 Amazon DynamoDB 提供了一个低级别接口,其方法与低级别 DynamoDB API 请求非常相似。
在某些情况下,您需要使用 数据类型描述符 识别数据类型,例如 S 对于字符串,N 对于数字。
package com.amazonaws.codesamples;
import java.util.HashMap;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemResult;
public class MusicLowLevelDemo {
public static void main(String[] args) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
HashMap<String, AttributeValue> key = new HashMap<String, AttributeValue>();
key.put("Artist", new AttributeValue().withS("No One You Know"));
key.put("SongTitle", new AttributeValue().withS("Call Me Today"));
GetItemRequest request = new GetItemRequest()
.withTableName("Music")
.withKey(key);
try {
GetItemResult result = client.getItem(request);
if (result && result.getItem() != null) {
AttributeValue year = result.getItem().get("Year");
System.out.println("The song was released in " + year.getN());
} else {
System.out.println("No matching song was found");
}
} catch (Exception e) {
System.err.println("Unable to retrieve data: ");
System.err.println(e.getMessage());
}
}
}
许多 AWS SDK 提供文档接口,允许您对表和索引执行数据层面操作(创建、读取、更新、删除)。对于文档接口,无需指定 数据类型描述符。数据类型由数据本身的语义隐含。这些 AWS SDK 还提供了一些方法,可以在 JSON 文档转换为 Amazon DynamoDB 本机数据类型之间轻松转换。
以下 Java 程序使用 AWS SDK for Java 的文档接口。程序创建一个 Table 对象,表示 Music 表,然后要求该对象使用 GetItem 检索歌曲。然后程序打印该歌曲的发行年份。
com.amazonaws.services.dynamodbv2.document.DynamoDB 类实施 DynamoDB 文档接口。
注意DynamoDB充当一个围绕低级别客户端的包装程序 (AmazonDynamoDB)。
package com.amazonaws.codesamples.gsg;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.GetItemOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
public class MusicDocumentDemo {
public static void main(String[] args) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB docClient = new DynamoDB(client);
Table table = docClient.getTable("Music");
GetItemOutcome outcome = table.getItemOutcome(
"Artist", "No One You Know",
"SongTitle", "Call Me Today");
int year = outcome.getItem().getInt("Year");
System.out.println("The song was released in " + year);
}
}
如果不直接执行数据层面操作,一些 AWS SDK 提供对象持久化接口。相反,您可以创建表示 Amazon DynamoDB 表和索引中项目的对象,并且仅与这些对象进行交互。这允许您编写以对象为中心的代码,而不是以数据库为中心的代码。
以下 Java 程序使用 DynamoDBMapper,AWS SDK for Java 的对象持久化接口。MusicItem 类表示 Music 表的项目。
package com.amazonaws.codesamples;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
@DynamoDBTable(tableName="Music")
public class MusicItem {
private String artist;
private String songTitle;
private String albumTitle;
private int year;
@DynamoDBHashKey(attributeName="Artist")
public String getArtist() { return artist;}
public void setArtist(String artist) {this.artist = artist;}
@DynamoDBRangeKey(attributeName="SongTitle")
public String getSongTitle() { return songTitle;}
public void setSongTitle(String songTitle) {this.songTitle = songTitle;}
@DynamoDBAttribute(attributeName = "AlbumTitle")
public String getAlbumTitle() { return albumTitle;}
public void setAlbumTitle(String albumTitle) {this.albumTitle = albumTitle;}
@DynamoDBAttribute(attributeName = "Year")
public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
}
然后,您可以实例化 MusicItem 对象,然后使用 DynamoDBMapper 的 load() 方法。然后,该程序打印该歌曲的发行年份。
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper 类实施 DynamoDB 对象持久化接口。注意DynamoDBMapper充当一个围绕低级别客户端的包装程序 (AmazonDynamoDB)。
package com.amazonaws.codesamples;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
public class MusicMapperDemo {
public static void main(String[] args) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDBMapper mapper = new DynamoDBMapper(client);
MusicItem keySchema = new MusicItem();
keySchema.setArtist("No One You Know");
keySchema.setSongTitle("Call Me Today");
try {
MusicItem result = mapper.load(keySchema);
if (result != null) {
System.out.println(
"The song was released in "+ result.getYear());
} else {
System.out.println("No matching song was found");
}
} catch (Exception e) {
System.err.println("Unable to retrieve data: ");
System.err.println(e.getMessage());
}
}
}
Amazon DynamoDB 低级别 API 是 DynamoDB 的协议级接口。在此级别,每个 HTTP(S) 请求的格式必须正确并带有有效的数字签名。
AWS SDK 代表您构建低级 DynamoDB API 请求并处理来自 DynamoDB 的响应。这可让您专注于应用程序逻辑而不是低级详细信息。不过,您仍可通过大致了解低级 DynamoDB API 的工作方式获益。
注意:
DynamoDB Streams 具有自己的低级别 API,此 API 独立于 DynamoDB 的低级别 API 且完全受 AWS SDK
支持。
这里不对DynamoDB 低级 API做过多介绍,知道他就是个http接口就可以了,通过http请求实现和数据库交互。
错误组成部分:
程序发送请求后,DynamoDB 会尝试处理该请求。如果请求成功,DynamoDB 将返回一个 HTTP 成功状态代码 (200 OK),以及所请求操作的结果。
如果请求失败,DynamoDB 会返回一个错误。每个错误包含三个部分:
AWS SDK 负责将错误传播到应用程序,以便您能执行适当操作。例如,在 Java 程序中,您可以编写 try-catch 逻辑以处理 ResourceNotFoundException。
参考错误响应处理
DynamoDB 表是无架构的(主键除外),因此,表中的项目可具有不同的属性、大小和数据类型。
项目的总大小是其属性名称和值的长度总和,加上任何适用的开销,如下所述。您可以使用以下准则来估算属性大小:
通过 Amazon DynamoDB 生存时间 (TTL),您可以定义每个项目的时间戳,以确定何时不再需要某个项目。在指定时间戳的日期和时间之后,DynamoDB 会立即从表中删除相应项目,而不会消耗任何写入吞吐量。提供 TTL 无需任何额外成本,它通过仅保留符合工作负载需求的项目来减少存储的数据量。
如果存储的项目在特定时间后不再相关,TTL 将非常有用。以下是 TTL 使用案例:
在 DynamoDB 表上启用 TTL 时,必须标识此服务在确定项目是否符合过期条件时将查找的特定属性名称。在表上启用 TTL 后,每个分区扫描程序后台进程都会自动持续评估表中项目的过期状态。
1、扫描程序后台进程将 Unix纪元时间格式(单位秒)的当前时间与项目的用户定义的 属性中存储的时间进行比较。
如果属性是 Number数据类型时,属性的值是 Unix 历元时间格式,并以秒为单位,并且时间戳值比当前时间早,但不超过五年或更长(为了避免由于格式错误的 TTL值而导致可能意外删除),则该项目设置为过期。有关设置 TL 属性格式的详细信息,请参阅 设置项目的 TTL 属性的格式。
2、第二个后台进程将扫描过期项目并将其删除。这两个进程都在后台自动进行,不会影响表的读取或写入流量,也不会产生费用成本。
从表中删除项目时,会同时执行两项后台操作:
使用 TTL 时,大部分艰巨的工作都是由 DynamoDB 代表您在幕后完成的。但是,您应该知道一些注意事项,以帮助您顺利地进行实施。
在表上启用 TTL 时,DynamoDB 要求您标识此服务在确定项目是否符合过期条件时将查找的特定属性名称。此外,进一步的要求可确保后台 TTL 进程使用 TTL 属性的值。要让项目符合通过 TTL 过期的资格:
参考链接:启用生存时间