aws-sdk-java-v2-dynamodb

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AWS SDK for Java 2.x - Amazon DynamoDB

AWS SDK for Java 2.x - Amazon DynamoDB

When to Use

适用场景

Use this skill when:
  • Creating, updating, or deleting DynamoDB tables
  • Performing CRUD operations on DynamoDB items
  • Querying or scanning tables
  • Working with Global Secondary Indexes (GSI) or Local Secondary Indexes (LSI)
  • Implementing batch operations for efficiency
  • Using DynamoDB transactions
  • Integrating DynamoDB with Spring Boot applications
  • Working with DynamoDB Enhanced Client for type-safe operations
在以下场景中使用本技能:
  • 创建、更新或删除DynamoDB表
  • 对DynamoDB条目执行CRUD操作
  • 查询或扫描表
  • 使用全局二级索引(GSI)或本地二级索引(LSI)
  • 实现批量操作以提升效率
  • 使用DynamoDB事务
  • 将DynamoDB与Spring Boot应用集成
  • 使用DynamoDB增强型客户端执行类型安全操作

Dependencies

依赖项

Add to
pom.xml
:
xml
<!-- Low-level DynamoDB client -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>dynamodb</artifactId>
</dependency>

<!-- Enhanced client (recommended) -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>dynamodb-enhanced</artifactId>
</dependency>
添加至
pom.xml
:
xml
<!-- Low-level DynamoDB client -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>dynamodb</artifactId>
</dependency>

<!-- Enhanced client (recommended) -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>dynamodb-enhanced</artifactId>
</dependency>

Client Setup

客户端配置

Low-Level Client

基础客户端

java
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

DynamoDbClient dynamoDb = DynamoDbClient.builder()
    .region(Region.US_EAST_1)
    .build();
java
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

DynamoDbClient dynamoDb = DynamoDbClient.builder()
    .region(Region.US_EAST_1)
    .build();

Enhanced Client (Recommended)

增强型客户端(推荐使用)

java
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;

DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
    .dynamoDbClient(dynamoDb)
    .build();
java
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;

DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
    .dynamoDbClient(dynamoDb)
    .build();

Entity Mapping

实体映射

To define DynamoDB entities, use
@DynamoDbBean
annotation:
java
@DynamoDbBean
public class Customer {

    @DynamoDbPartitionKey
    private String customerId;

    @DynamoDbAttribute("customer_name")
    private String name;

    private String email;

    @DynamoDbSortKey
    private String orderId;

    // Getters and setters
}
For complex entity mapping with GSIs and custom converters, see Entity Mapping Reference.
要定义DynamoDB实体,请使用
@DynamoDbBean
注解:
java
@DynamoDbBean
public class Customer {

    @DynamoDbPartitionKey
    private String customerId;

    @DynamoDbAttribute("customer_name")
    private String name;

    private String email;

    @DynamoDbSortKey
    private String orderId;

    // Getters and setters
}
有关包含GSI和自定义转换器的复杂实体映射,请参阅实体映射参考文档

CRUD Operations

CRUD操作

Basic Operations

基础操作

java
// Create or update item
DynamoDbTable<Customer> table = enhancedClient.table("Customers", TableSchema.fromBean(Customer.class));
table.putItem(customer);

// Get item
Customer result = table.getItem(Key.builder().partitionValue(customerId).build());

// Update item
return table.updateItem(customer);

// Delete item
table.deleteItem(Key.builder().partitionValue(customerId).build());
java
// Create or update item
DynamoDbTable<Customer> table = enhancedClient.table("Customers", TableSchema.fromBean(Customer.class));
table.putItem(customer);

// Get item
Customer result = table.getItem(Key.builder().partitionValue(customerId).build());

// Update item
return table.updateItem(customer);

// Delete item
table.deleteItem(Key.builder().partitionValue(customerId).build());

Composite Key Operations

复合键操作

java
// Get item with composite key
Order order = table.getItem(Key.builder()
    .partitionValue(customerId)
    .sortValue(orderId)
    .build());
java
// Get item with composite key
Order order = table.getItem(Key.builder()
    .partitionValue(customerId)
    .sortValue(orderId)
    .build());

Query Operations

查询操作

Basic Query

基础查询

java
import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional;

QueryConditional queryConditional = QueryConditional
    .keyEqualTo(Key.builder()
        .partitionValue(customerId)
        .build());

List<Order> orders = table.query(queryConditional).items().stream()
    .collect(Collectors.toList());
java
import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional;

QueryConditional queryConditional = QueryConditional
    .keyEqualTo(Key.builder()
        .partitionValue(customerId)
        .build());

List<Order> orders = table.query(queryConditional).items().stream()
    .collect(Collectors.toList());

Advanced Query with Filters

带过滤器的高级查询

java
import software.amazon.awssdk.enhanced.dynamodb.Expression;

Expression filter = Expression.builder()
    .expression("status = :pending")
    .putExpressionValue(":pending", AttributeValue.builder().s("PENDING").build())
    .build();

List<Order> pendingOrders = table.query(r -> r
    .queryConditional(queryConditional)
    .filterExpression(filter))
    .items().stream()
    .collect(Collectors.toList());
For detailed query patterns, see Advanced Operations Reference.
java
import software.amazon.awssdk.enhanced.dynamodb.Expression;

Expression filter = Expression.builder()
    .expression("status = :pending")
    .putExpressionValue(":pending", AttributeValue.builder().s("PENDING").build())
    .build();

List<Order> pendingOrders = table.query(r -> r
    .queryConditional(queryConditional)
    .filterExpression(filter))
    .items().stream()
    .collect(Collectors.toList());
有关详细的查询模式,请参阅高级操作参考文档

Scan Operations

扫描操作

java
// Scan all items
List<Customer> allCustomers = table.scan().items().stream()
    .collect(Collectors.toList());

// Scan with filter
Expression filter = Expression.builder()
    .expression("points >= :minPoints")
    .putExpressionValue(":minPoints", AttributeValue.builder().n("1000").build())
    .build();

List<Customer> vipCustomers = table.scan(r -> r.filterExpression(filter))
    .items().stream()
    .collect(Collectors.toList());
java
// Scan all items
List<Customer> allCustomers = table.scan().items().stream()
    .collect(Collectors.toList());

// Scan with filter
Expression filter = Expression.builder()
    .expression("points >= :minPoints")
    .putExpressionValue(":minPoints", AttributeValue.builder().n("1000").build())
    .build();

List<Customer> vipCustomers = table.scan(r -> r.filterExpression(filter))
    .items().stream()
    .collect(Collectors.toList());

Batch Operations

批量操作

Batch Get

批量读取

java
import software.amazon.awssdk.enhanced.dynamodb.model.*;

List<Key> keys = customerIds.stream()
    .map(id -> Key.builder().partitionValue(id).build())
    .collect(Collectors.toList());

ReadBatch.Builder<Customer> batchBuilder = ReadBatch.builder(Customer.class)
    .mappedTableResource(table);

keys.forEach(batchBuilder::addGetItem);

BatchGetResultPageIterable result = enhancedClient.batchGetItem(r ->
    r.addReadBatch(batchBuilder.build()));

List<Customer> customers = result.resultsForTable(table).stream()
    .collect(Collectors.toList());
java
import software.amazon.awssdk.enhanced.dynamodb.model.*;

List<Key> keys = customerIds.stream()
    .map(id -> Key.builder().partitionValue(id).build())
    .collect(Collectors.toList());

ReadBatch.Builder<Customer> batchBuilder = ReadBatch.builder(Customer.class)
    .mappedTableResource(table);

keys.forEach(batchBuilder::addGetItem);

BatchGetResultPageIterable result = enhancedClient.batchGetItem(r ->
    r.addReadBatch(batchBuilder.build()));

List<Customer> customers = result.resultsForTable(table).stream()
    .collect(Collectors.toList());

Batch Write

批量写入

java
WriteBatch.Builder<Customer> batchBuilder = WriteBatch.builder(Customer.class)
    .mappedTableResource(table);

customers.forEach(batchBuilder::addPutItem);

enhancedClient.batchWriteItem(r -> r.addWriteBatch(batchBuilder.build()));
java
WriteBatch.Builder<Customer> batchBuilder = WriteBatch.builder(Customer.class)
    .mappedTableResource(table);

customers.forEach(batchBuilder::addPutItem);

enhancedClient.batchWriteItem(r -> r.addWriteBatch(batchBuilder.build()));

Transactions

事务操作

Transactional Write

事务写入

java
enhancedClient.transactWriteItems(r -> r
    .addPutItem(customerTable, customer)
    .addPutItem(orderTable, order));
java
enhancedClient.transactWriteItems(r -> r
    .addPutItem(customerTable, customer)
    .addPutItem(orderTable, order));

Transactional Read

事务读取

java
TransactGetItemsEnhancedRequest request = TransactGetItemsEnhancedRequest.builder()
    .addGetItem(customerTable, customerKey)
    .addGetItem(orderTable, orderKey)
    .build();

List<Document> results = enhancedClient.transactGetItems(request);
java
TransactGetItemsEnhancedRequest request = TransactGetItemsEnhancedRequest.builder()
    .addGetItem(customerTable, customerKey)
    .addGetItem(orderTable, orderKey)
    .build();

List<Document> results = enhancedClient.transactGetItems(request);

Spring Boot Integration

Spring Boot集成

Configuration

配置类

java
@Configuration
public class DynamoDbConfiguration {

    @Bean
    public DynamoDbClient dynamoDbClient() {
        return DynamoDbClient.builder()
            .region(Region.US_EAST_1)
            .build();
    }

    @Bean
    public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
        return DynamoDbEnhancedClient.builder()
            .dynamoDbClient(dynamoDbClient)
            .build();
    }
}
java
@Configuration
public class DynamoDbConfiguration {

    @Bean
    public DynamoDbClient dynamoDbClient() {
        return DynamoDbClient.builder()
            .region(Region.US_EAST_1)
            .build();
    }

    @Bean
    public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
        return DynamoDbEnhancedClient.builder()
            .dynamoDbClient(dynamoDbClient)
            .build();
    }
}

Repository Pattern

仓库模式

java
@Repository
public class CustomerRepository {

    private final DynamoDbTable<Customer> customerTable;

    public CustomerRepository(DynamoDbEnhancedClient enhancedClient) {
        this.customerTable = enhancedClient.table("Customers", TableSchema.fromBean(Customer.class));
    }

    public void save(Customer customer) {
        customerTable.putItem(customer);
    }

    public Optional<Customer> findById(String customerId) {
        Key key = Key.builder().partitionValue(customerId).build();
        return Optional.ofNullable(customerTable.getItem(key));
    }
}
For comprehensive Spring Boot integration patterns, see Spring Boot Integration Reference.
java
@Repository
public class CustomerRepository {

    private final DynamoDbTable<Customer> customerTable;

    public CustomerRepository(DynamoDbEnhancedClient enhancedClient) {
        this.customerTable = enhancedClient.table("Customers", TableSchema.fromBean(Customer.class));
    }

    public void save(Customer customer) {
        customerTable.putItem(customer);
    }

    public Optional<Customer> findById(String customerId) {
        Key key = Key.builder().partitionValue(customerId).build();
        return Optional.ofNullable(customerTable.getItem(key));
    }
}
有关完整的Spring Boot集成模式,请参阅Spring Boot集成参考文档

Testing

测试

Unit Testing with Mocks

使用Mock进行单元测试

java
@ExtendWith(MockitoExtension.class)
class CustomerServiceTest {

    @Mock
    private DynamoDbClient dynamoDbClient;

    @Mock
    private DynamoDbEnhancedClient enhancedClient;

    @Mock
    private DynamoDbTable<Customer> customerTable;

    @InjectMocks
    private CustomerService customerService;

    @Test
    void saveCustomer_ShouldReturnSavedCustomer() {
        // Arrange
        when(enhancedClient.table(anyString(), any(TableSchema.class)))
            .thenReturn(customerTable);

        Customer customer = new Customer("123", "John Doe", "john@example.com");

        // Act
        Customer result = customerService.saveCustomer(customer);

        // Assert
        assertNotNull(result);
        verify(customerTable).putItem(customer);
    }
}
java
@ExtendWith(MockitoExtension.class)
class CustomerServiceTest {

    @Mock
    private DynamoDbClient dynamoDbClient;

    @Mock
    private DynamoDbEnhancedClient enhancedClient;

    @Mock
    private DynamoDbTable<Customer> customerTable;

    @InjectMocks
    private CustomerService customerService;

    @Test
    void saveCustomer_ShouldReturnSavedCustomer() {
        // Arrange
        when(enhancedClient.table(anyString(), any(TableSchema.class)))
            .thenReturn(customerTable);

        Customer customer = new Customer("123", "John Doe", "john@example.com");

        // Act
        Customer result = customerService.saveCustomer(customer);

        // Assert
        assertNotNull(result);
        verify(customerTable).putItem(customer);
    }
}

Integration Testing with LocalStack

使用LocalStack进行集成测试

java
@Testcontainers
@SpringBootTest
class DynamoDbIntegrationTest {

    @Container
    static LocalStackContainer localstack = new LocalStackContainer(
        DockerImageName.parse("localstack/localstack:3.0"))
        .withServices(LocalStackContainer.Service.DYNAMODB);

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("aws.endpoint",
            () -> localstack.getEndpointOverride(LocalStackContainer.Service.DYNAMODB).toString());
    }

    @Autowired
    private DynamoDbEnhancedClient enhancedClient;

    @Test
    void testCustomerCRUDOperations() {
        // Test implementation
    }
}
For detailed testing strategies, see Testing Strategies.
java
@Testcontainers
@SpringBootTest
class DynamoDbIntegrationTest {

    @Container
    static LocalStackContainer localstack = new LocalStackContainer(
        DockerImageName.parse("localstack/localstack:3.0"))
        .withServices(LocalStackContainer.Service.DYNAMODB);

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("aws.endpoint",
            () -> localstack.getEndpointOverride(LocalStackContainer.Service.DYNAMODB).toString());
    }

    @Autowired
    private DynamoDbEnhancedClient enhancedClient;

    @Test
    void testCustomerCRUDOperations() {
        // Test implementation
    }
}
有关详细的测试策略,请参阅测试策略文档

Best Practices

最佳实践

  1. Use Enhanced Client: Provides type-safe operations with less boilerplate
  2. Design partition keys carefully: Distribute data evenly across partitions
  3. Use composite keys: Leverage sort keys for efficient queries
  4. Create GSIs strategically: Support different access patterns
  5. Use batch operations: Reduce API calls for multiple items
  6. Implement pagination: For large result sets use pagination
  7. Use transactions: For operations that must be atomic
  8. Avoid scans: Prefer queries with proper indexes
  9. Handle conditional writes: Prevent race conditions
  10. Use proper error handling: Handle exceptions like
    ProvisionedThroughputExceeded
  1. 使用增强型客户端:提供类型安全操作,减少样板代码
  2. 谨慎设计分区键:确保数据在分区间均匀分布
  3. 使用复合键:利用排序键实现高效查询
  4. 合理创建GSI:支持不同的数据访问模式
  5. 使用批量操作:减少多条目操作的API调用次数
  6. 实现分页:针对大数据集使用分页功能
  7. 使用事务:确保操作的原子性
  8. 避免全表扫描:优先使用带合适索引的查询
  9. 处理条件写入:防止竞态条件
  10. 完善错误处理:处理
    ProvisionedThroughputExceeded
    等异常

Common Patterns

常见模式

Conditional Operations

条件操作

java
PutItemEnhancedRequest request = PutItemEnhancedRequest.builder(table)
    .item(customer)
    .conditionExpression("attribute_not_exists(customerId)")
    .build();

table.putItemWithRequestBuilder(request);
java
PutItemEnhancedRequest request = PutItemEnhancedRequest.builder(table)
    .item(customer)
    .conditionExpression("attribute_not_exists(customerId)")
    .build();

table.putItemWithRequestBuilder(request);

Pagination

分页

java
ScanEnhancedRequest request = ScanEnhancedRequest.builder()
    .limit(100)
    .build();

PaginatedScanIterable<Customer> results = table.scan(request);
results.stream().forEach(page -> {
    // Process each page
});
java
ScanEnhancedRequest request = ScanEnhancedRequest.builder()
    .limit(100)
    .build();

PaginatedScanIterable<Customer> results = table.scan(request);
results.stream().forEach(page -> {
    // Process each page
});

Performance Considerations

性能注意事项

  • Monitor read/write capacity units
  • Implement exponential backoff for retries
  • Use proper pagination for large datasets
  • Consider eventual consistency for reads
  • Use
    ReturnConsumedCapacity
    to monitor capacity usage
  • 监控读写容量单元
  • 实现指数退避重试机制
  • 针对大数据集使用合适的分页方式
  • 读取操作可考虑最终一致性
  • 使用
    ReturnConsumedCapacity
    监控容量使用情况

Related Skills

相关技能

  • aws-sdk-java-v2-core 
    - Core AWS SDK patterns
  • spring-data-jpa
    - Alternative data access patterns
  • unit-test-service-layer
    - Service testing patterns
  • unit-test-wiremock-rest-api
    - Testing external APIs
  • aws-sdk-java-v2-core 
    - 核心AWS SDK使用模式
  • spring-data-jpa
    - 替代的数据访问模式
  • unit-test-service-layer
    - 服务层单元测试
  • unit-test-wiremock-rest-api
    - 外部API测试

References

参考资料

For detailed implementations, see the references folder:
  • Entity Mapping Reference
  • Advanced Operations Reference
  • Spring Boot Integration Reference
  • Testing Strategies
有关详细实现,请参阅参考文件夹:
  • 实体映射参考文档
  • 高级操作参考文档
  • Spring Boot集成参考文档
  • 测试策略文档