参考资料
- https://docs.amazonaws.cn/zh_cn/sdk-for-java/latest/developer-guide/setup-project-maven.html
初始化环境
创建maven项目
mvn org.apache.maven.plugins:maven-archetype-plugin:3.1.2:generate \
-DarchetypeArtifactId="maven-archetype-quickstart" \
-DarchetypeGroupId="org.apache.maven.archetypes" \
-DarchetypeVersion="1.4" \
-DgroupId="com.zhojiew.myapp" \
-DartifactId="ddbapp"
加载依赖
https://mvnrepository.com/artifact/software.amazon.awssdk/bom/latest
配置maven依赖
<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.20.21</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb-enhanced</artifactId>
</dependency>
</dependencies>
...
</project>
java低级api操作
官方文档和示例仓库中有非常详细的样例,例如以下创建删除表,注意流程如下
- 初始化区域和凭证
- 初始化ddb客户端
- 构造请求参数
- 发送请求接受响应
// 初始化客户端
Region region = Region.CN_NORTH_1;
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
DynamoDbClient ddb = DynamoDbClient.builder().region(region).build();
DynamoDbWaiter dbWaiter = ddb.waiter();
//初始化ddb客户端请求,创建复合主键表
CreateTableRequest request = CreateTableRequest.builder()
//设置属性字段
.attributeDefinitions(
AttributeDefinition.builder().attributeName(keypart).attributeType(ScalarAttributeType.S).build(),
AttributeDefinition.builder().attributeName(keyrange).attributeType(ScalarAttributeType.S).build()
)
// 指定分区和排序键
.keySchema(
KeySchemaElement.builder().attributeName(keypart).keyType(KeyType.HASH).build(),
KeySchemaElement.builder().attributeName(keyrange).keyType(KeyType.RANGE).build()
)
// 预置读写容量5
.provisionedThroughput(ProvisionedThroughput.builder()
.readCapacityUnits(new Long(5))
.writeCapacityUnits(new Long(5))
.build())
.tableName(tableName)
.build();
// 返回值
String newTable = "";
try {
// 创建表
CreateTableResponse response = ddb.createTable(request);
DescribeTableRequest tableRequest = DescribeTableRequest.builder()
.tableName(tableName)
.build();
// 等待请求返回
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);
}
// 初始化删除请求
DeleteTableRequest request = DeleteTableRequest.builder()
.tableName("ThreeKingdoms")
.build();
// 删除表
try {
ddb.deleteTable(request);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
查询item(同步)
public static void getDynamoDBItem(DynamoDbClient ddb,String tableName,String key,String keyVal ) {
HashMap<String,AttributeValue> keyToGet = new HashMap<String,AttributeValue>();
// 初始化键参数
keyToGet.put(key, AttributeValue.builder()
.s(keyVal).build());
// 构造请求
GetItemRequest request = GetItemRequest.builder()
.key(keyToGet)
.tableName(tableName)
.build();
try {
Map<String,AttributeValue> returnedItem = ddb.getItem(request).item();
// 输出item
if (returnedItem != null) {
Set<String> keys = returnedItem.keySet();
System.out.println("Amazon DynamoDB table attributes: \n");
for (String key1 : keys) {
System.out.format("%s: %s\n", key1, returnedItem.get(key1).toString());
}
} else {
System.out.format("No item found with the key %s!\n", key);
}
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
插入item
public static void putItemInTable(DynamoDbClient ddb,
String tableName,
String key,
String keyVal,
String albumTitle,
String albumTitleValue,
String awards,
String awardVal,
String songTitle,
String songTitleVal){
HashMap<String,AttributeValue> itemValues = new HashMap<String,AttributeValue>();
// 构造item
itemValues.put(key, AttributeValue.builder().s(keyVal).build());
itemValues.put(songTitle, AttributeValue.builder().s(songTitleVal).build());
itemValues.put(albumTitle, AttributeValue.builder().s(albumTitleValue).build());
itemValues.put(awards, AttributeValue.builder().s(awardVal).build());
// 给否在请求
PutItemRequest request = PutItemRequest.builder()
.tableName(tableName)
.item(itemValues)
.build();
try {
ddb.putItem(request);
System.out.println(tableName +" was successfully updated");
} catch (ResourceNotFoundException e) {
...略
}
}
从以上的流程可知,低等级的api需要手动构造请求参数和发送请求,属于一种过程式的客户端。用户需要控制请求的具体参数,实际上就是awscli的java版本调用
- 对于创建表来说,需要指定表名,键名,读写容量等。
- 对于item的操作会更复杂,需要手动构造item的请求,尽管有batch操作的api仍旧较为繁琐。
java高级api操作
我们主要来看java的高级api操作
https://docs.amazonaws.cn/zh_cn/sdk-for-java/latest/developer-guide/examples-dynamodb-enhanced.html
DynamoDB 增强版客户端是一个高级库,是Amazon SDK for Java版本 2 (v2) 的一部分。它提供一种将客户端类映射到 DynamoDB 表的直接方法。您可以在代码中定义表与其相应模型类之间的关系。定义这些关系后,您可以直观地对 DynamoDB 中的表或项目执行各种创建、读取、更新或删除 (CRUD) 操作
需要在java项目中额外导入依赖
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb-enhanced</artifactId>
</dependency>
DynamoDbEnhancedClient实例用于处理 DynamoDB 表和映射类。DynamoDbEnhancedClient
从现有DynamoDbClient
对象创建
之前接触过一些SSM和SSH框架,有点类似与hibernate的DAO映射,通过注解完成POJO和item的映射,用户就不需要写CRUD操作了,更像是一种声明式的写法。
第一步生成TableSchema
- v2的java sdk包括一组注解用来快速生成
TableSchema
用于将类映射到表的注释 - 例如以下POJO,注解指定了分区键和排序键
@DynamoDbBean
public class Customer {
private String id;
private String name;
private String email;
private Instant regDate;
@DynamoDbPartitionKey
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getCustName() {
return this.name;
}
public void setCustName(String name) {
this.name = name;
}
@DynamoDbSortKey
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public Instant getRegistrationDate() {
return regDate;
}
public void setRegistrationDate(Instant registrationDate) {
this.regDate = registrationDate;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", email=" + email
+ ", regDate=" + regDate + "]";
}
}
创建表
https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/enhanced/EnhancedCreateTable.java
public static void main(String[] args) {
// 初始化客户端
DynamoDbClient ddb = DynamoDbClient.builder().region(Region.CN_NORTH_1).build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
// 从Bean tableschema创建表请求
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
// 创建表
customerTable.createTable(builder -> builder
.provisionedThroughput(b -> b
.readCapacityUnits(5L)
.writeCapacityUnits(5L)
.build())
);
System.out.println("Waiting for table creation...");
// 等待表创建,获取响应
try (DynamoDbWaiter waiter = DynamoDbWaiter.create()) {
ResponseOrException<DescribeTableResponse> response = waiter
.waitUntilTableExists(builder -> builder.tableName("Customer").build())
.matched();
DescribeTableResponse tableDescription = response.response().orElseThrow(
() -> new RuntimeException("Customer table was not created."));
System.out.println(tableDescription.table().tableName() + " was created.");
}
}
控制台查看表创建结果
- 默认情况下,类名和表名一致
- 字段名和键名一致
再来看看item的相关示例
- 此时我们只需要构造实例,然后使用高级客户端插入item即可
- 比起低级api开发效率更高了
DynamoDbClient ddb = DynamoDbClient.builder().region(Region.CN_NORTH_1).build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
try {
DynamoDbTable<Customer> custTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
// 构造item
LocalDate localDate = LocalDate.parse("2020-04-07");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
Customer custRecord = new Customer();
custRecord.setCustName("Tom red");
custRecord.setId("id101");
custRecord.setEmail("tred@noserver.com");
custRecord.setRegistrationDate(instant);
// 在表中插入item
custTable.putItem(custRecord);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
查看item插入成功
rust低级api操作
不得不说,java低级api的写法有点繁琐,对比下rust看看
创建表
说实话下面的这段代码咱只能看懂和java类似的部分,至于tokio和strucopt看不太懂,需要继续学习下rust,现在先抄着用吧
话说就这一点东西debug编译之后有187M,而release只有17M
use aws_sdk_dynamodb::{
model::{
AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType,
},
Client, Error,
};
use aws_config::meta::region::RegionProviderChain;
use aws_sdk_dynamodb::{ Region, PKG_VERSION};
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
struct Opt {
/// The AWS Region.
#[structopt(short, long)]
region: Option<String>,
/// Whether to display additional information.
#[structopt(short, long)]
verbose: bool,
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt::init();
let Opt { region, verbose } = Opt::from_args();
let region_provider = RegionProviderChain::first_try(region.map(Region::new))
.or_default_provider()
.or_else(Region::new("cn-north-1"));
println!();
if verbose {
println!("DynamoDB client version: {}", PKG_VERSION);
println!(
"Region: {}",
region_provider.region().await.unwrap().as_ref()
);
println!();
}
let shared_config = aws_config::from_env().region(region_provider).load().await;
let client = Client::new(&shared_config);
list_tables(&client).await?;
create_table(&client).await
}
async fn list_tables(client: &Client) -> Result<(), Error> {
let tables = client.list_tables().send().await?;
println!("Current DynamoDB tables: {:?}", tables);
Ok(())
}
async fn create_table(client: &Client) -> Result<(), Error> {
let new_table = client
.create_table()
.table_name("test-table")
.key_schema(
KeySchemaElement::builder()
.attribute_name("k")
.key_type(KeyType::Hash)
.build(),
)
.attribute_definitions(
AttributeDefinition::builder()
.attribute_name("k")
.attribute_type(ScalarAttributeType::S)
.build(),
)
.provisioned_throughput(
ProvisionedThroughput::builder()
.write_capacity_units(5)
.read_capacity_units(5)
.build(),
)
.send()
.await?;
println!(
"new table: {:#?}",
&new_table.table_description().unwrap().table_arn().unwrap()
);
Ok(())
}
执行试试
$ ./rustdemo
2023-03-11T11:22:12.870149Z INFO aws_credential_types::cache::lazy_caching: credentials cache miss occurred; retrieved new AWS credentials (took 7.115433ms)
Current DynamoDB tables: ListTablesOutput { table_names: Some(["AppSyncCommentTable-JiXcP7eW", "AppSyncEventTable-JiXcP7eW", "Music", "http-crud-tutorial-items", "learnddb"]), last_evaluated_table_name: None }
new table: "arn:aws-cn:dynamodb:cn-north-1:xxxxxxxxxxx:table/test-table"
总结一下
-
api的使用就是照着文档抄没什么好说的,毕竟是不开源的东西会用就行,最重要的还是理解不同层次的api的区别
-
之后可以将ayysync,dynamodb和apigateway集成看看有什么火花