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();
			
			// 输出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) 操作

aws dynamodb java低等级api和高级客户端api的使用_第1张图片

需要在java项目中额外导入依赖


      software.amazon.awssdk
      dynamodb-enhanced

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.");  
    }  
}

控制台查看表创建结果

  • 默认情况下,类名和表名一致
  • 字段名和键名一致

aws dynamodb java低等级api和高级客户端api的使用_第2张图片

再来看看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("[email protected]");  
    custRecord.setRegistrationDate(instant);  
  
  // 在表中插入item
  custTable.putItem(custRecord);  
  
} catch (DynamoDbException e) {  
    System.err.println(e.getMessage());  
    System.exit(1);  
}

查看item插入成功

aws dynamodb java低等级api和高级客户端api的使用_第3张图片

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集成看看有什么火花

你可能感兴趣的:(AWS,java,aws,maven)