aws dynamodb java低等级api和高级客户端api的使用
参考资料
- 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();// 输出itemif (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>();// 构造itemitemValues.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); // 在表中插入itemcustTable.putItem(custRecord); } catch (DynamoDbException e) { System.err.println(e.getMessage()); System.exit(1);
}
查看item插入成功
rust低级api操作
不得不说,java低级api的写法有点繁琐,对比下rust看看
创建表
说实话下面的这段代码咱只能看懂和java类似的部分,至于tokio和strucopt看不太懂,需要继续学习下rust,现在先抄着用吧
$ cat Cargo.toml
[package]
name = "rustdemo"
version = "0.1.0"
edition = "2021"[dependencies]
aws-config = "0.54.1"
aws-sdk-dynamodb = "0.24.0"
structopt = "0.3.26"
tokio = { version = "1.26.0", features = ["full"] }
tracing-subscriber = "0.3.16"
话说就这一点东西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集成看看有什么火花