aws-sdk-java-v2-dynamodb
AWS SDK for Java 2.x を使用した Amazon DynamoDB の実装パターンを提供します。DynamoDB テーブルの作成・クエリ・スキャン・CRUD 操作、インデックスの活用、バッチ操作、トランザクション処理、または Spring Boot アプリケーションとの統合を行う際に使用してください。
description の原文を見る
Provides Amazon DynamoDB patterns using AWS SDK for Java 2.x. Use when creating, querying, scanning, or performing CRUD operations on DynamoDB tables, working with indexes, batch operations, transactions, or integrating with Spring Boot applications.
SKILL.md 本文
AWS SDK for Java 2.x - Amazon DynamoDB
概要
AWS SDK for Java 2.x の Enhanced Client を使用した DynamoDB パターンを提供します。型安全な CRUD、クエリ、バッチ操作、トランザクション、Spring Boot 統合に対応しています。
使用する場合
- DynamoDB アイテムの CRUD 操作
- ソートキーまたは GSI でテーブルをクエリする
- 複数アイテムのバッチ操作
- テーブル間のアトミックトランザクション
- DynamoDB と Spring Boot の統合
手順
pom.xmlに AWS SDK DynamoDB 依存関係を追加- クライアント設定(低レベルまたは Enhanced Client)
@DynamoDbBeanアノテーションでエンティティクラスを定義DynamoDbTableを使用して操作を実行(CRUD、クエリ、スキャン、バッチ、トランザクション)- リトライロジックと指数バックオフで部分的な失敗を処理
- Spring Boot 統合にはリポジトリパターンを使用
依存関係
pom.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>
クライアント設定
低レベルクライアント
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(推奨)
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(dynamoDb)
.build();
エンティティマッピング
@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 操作
基本操作
// アイテムの作成または更新
DynamoDbTable<Customer> table = enhancedClient.table("Customers", TableSchema.fromBean(Customer.class));
table.putItem(customer);
// アイテムを取得
Customer result = table.getItem(Key.builder().partitionValue(customerId).build());
// アイテムを更新
return table.updateItem(customer);
// アイテムを削除
table.deleteItem(Key.builder().partitionValue(customerId).build());
複合キー操作
// 複合キーでアイテムを取得
Order order = table.getItem(Key.builder()
.partitionValue(customerId)
.sortValue(orderId)
.build());
クエリ操作
基本クエリ
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());
フィルター付きの高度なクエリ
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());
詳細なクエリパターンについては、高度な操作リファレンスを参照してください。
スキャン操作
警告: スキャンはテーブル全体を読み取り、すべてのアイテムの読み取り容量を消費します。可能な限り、パーティションキーまたは GSI を使用したクエリ操作を優先してください。
スキャン前の検証:
- パーティションキーを使用したクエリがアクセスパターンに適切でないことを確認
- テーブルに十分なプロビジョニング読み取り容量があるか、またはオンデマンドモードを使用していることを確認
limit()を使用したページネーションで容量消費を制御することを検討
// すべてのアイテムをスキャン
List<Customer> allCustomers = table.scan().items().stream()
.collect(Collectors.toList());
// フィルター付きでスキャン
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());
バッチ操作
バッチ取得
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());
エラーハンドリング付きバッチ書き込み
WriteBatch.Builder<Customer> batchBuilder = WriteBatch.builder(Customer.class)
.mappedTableResource(table);
customers.forEach(batchBuilder::addPutItem);
BatchWriteItemEnhancedRequest request = BatchWriteItemEnhancedRequest.builder()
.addWriteBatch(batchBuilder.build())
.build();
BatchWriteResult result = enhancedClient.batchWriteItem(request);
// 検証: 未処理のアイテムをチェック
if (!result.writeResponsesForTable(table).isEmpty()) {
// 指数バックオフで未処理のアイテムを再試行
Map<String, AttributeValue> unprocessed = result.writeResponsesForTable(table).get(0)
.unprocessedAttributes();
if (unprocessed != null && !unprocessed.isEmpty()) {
enhancedClient.batchWriteItem(r -> r
.addWriteBatch(WriteBatch.builder(Customer.class)
.mappedTableResource(table)
.addPutItemFromItem(unprocessed)
.build()));
}
}
トランザクション
リトライ付きトランザクショナル書き込み
public void placeOrderWithRetry(Order order, Customer customer, int maxRetries) {
int attempt = 0;
while (attempt < maxRetries) {
try {
enhancedClient.transactWriteItems(r -> r
.addPutItem(customerTable, customer)
.addPutItem(orderTable, order));
return;
} catch (TransactionCanceledException e) {
if (e.cancellationReasons().stream()
.anyMatch(r -> r.code().equals("TransactionCanceledException")
&& r.message().contains("throughput"))) {
attempt++;
if (attempt < maxRetries) {
try { Thread.sleep((long) Math.pow(2, attempt) * 100); }
catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
}
} else {
throw e; // Non-retryable error
}
}
}
}
トランザクショナル読み取り
TransactGetItemsEnhancedRequest request = TransactGetItemsEnhancedRequest.builder()
.addGetItem(customerTable, customerKey)
.addGetItem(orderTable, orderKey)
.build();
List<Document> results = enhancedClient.transactGetItems(request);
Spring Boot 統合
設定
@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
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 統合リファレンスを参照してください。
テスト
モックを使用したユニットテスト
@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);
}
}
LocalStack を使用した統合テスト
@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
}
}
詳細なテスト戦略については、テスト戦略を参照してください。
ベストプラクティス
- Enhanced Client を使用: 定型的なコードが少ない型安全な操作
- 均等分散のためにパーティションキーを設計: ホットパーティションを回避
- スキャンよりクエリを優先: アクセスパターンに GSI を使用
- 25/100 の単位でバッチ処理: BatchGetItem は 100、BatchWriteItem はテーブルあたり 25 に制限
- 部分的な失敗を処理:
ProvisionedThroughputExceededに対して指数バックオフでリトライを実装 - 条件付き書き込みを使用:
attribute_not_exists(pk)で競合状態を防止
例
完全な CRUD リポジトリ
@Repository
public class UserRepository {
private final DynamoDbTable<User> userTable;
public UserRepository(DynamoDbEnhancedClient enhancedClient) {
this.userTable = enhancedClient.table("Users", TableSchema.fromBean(User.class));
}
public User save(User user) {
userTable.putItem(user);
return user;
}
public Optional<User> findById(String userId) {
Key key = Key.builder().partitionValue(userId).build();
return Optional.ofNullable(userTable.getItem(key));
}
public void deleteById(String userId) {
userTable.deleteItem(Key.builder().partitionValue(userId).build());
}
}
リトライ付き条件付き書き込み
public boolean createIfNotExists(User user) {
PutItemEnhancedRequest<User> request = PutItemEnhancedRequest.builder(User.class)
.item(user)
.conditionExpression("attribute_not_exists(userId)")
.build();
try {
userTable.putItemWithRequest(request);
return true;
} catch (ConditionalCheckFailedException e) {
return false; // Item already exists
}
}
制約と警告
- アイテムサイズ制限: DynamoDB アイテムは 400KB に制限
- パーティションキー設計: 不適切な設計はホットパーティションの原因となる
- バッチ制限: BatchGetItem 最大 100、BatchWriteItem テーブルあたり最大 25 アイテム
- トランザクションコスト: トランザクションは読み取り/書き込み容量ユニット 2 倍のコスト
- スキャン操作: スキャンは大量の読み取り容量を消費。必要な場合のみ使用
リファレンス
詳細な実装については、リファレンスフォルダを参照してください:
エンティティマッピングリファレンス高度な操作リファレンスSpring Boot 統合リファレンステスト戦略
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- giuseppe-trisciuoglio
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT
関連スキル
superpowers-streamer-cli
SuperPowers デスクトップストリーマーの npm パッケージをインストール、ログイン、実行、トラブルシューティングできます。ユーザーが npm から `superpowers-ai` をセットアップしたい場合、メールまたは電話でサインインもしくはアカウント作成を行いたい場合、ストリーマーを起動したい場合、表示されたコントロールリンクを開きたい場合、後で停止したい場合、またはソースコードへのアクセスなしに npm やランタイムの一般的な問題から復旧したい場合に使用します。
catc-client-ops
Catalyst Centerのクライアント操作・監視機能 - 有線・無線クライアントのリスト表示・フィルタリング、MACアドレスによる詳細なクライアント検索、クライアント数分析、時間軸での分析、SSIDおよび周波数帯によるフィルタリング、無線トラブルシューティング機能を提供します。MACアドレスやIPアドレスでのクライアント検索、サイト別やSSID別のクライアント数集計、無線周波数帯の分布分析、Wi-Fi信号の問題調査が必要な場合に活用できます。
ci-cd-and-automation
CI/CDパイプラインの設定を自動化します。ビルドおよびデプロイメントパイプラインの構築または変更時に使用できます。品質ゲートの自動化、CI内のテストランナー設定、またはデプロイメント戦略の確立が必要な場合に活用します。
shipping-and-launch
本番環境へのリリース準備を行います。本番環境へのデプロイ準備が必要な場合、リリース前チェックリストが必要な場合、監視機能の設定を行う場合、段階的なロールアウトを計画する場合、またはロールバック戦略が必要な場合に使用します。
linear-release-setup
Linear Releaseに向けたCI/CD設定を生成します。リリース追跡の設定、LinearのCIパイプライン構築、またはLinearリリースとのデプロイメント連携を実施する際に利用できます。GitHub Actions、GitLab CI、CircleCIなど複数のプラットフォームに対応しています。
tracking-application-response-times
API エンドポイント、データベースクエリ、サービスコール全体にわたるアプリケーションのレスポンスタイムを追跡・最適化できます。パフォーマンス監視やボトルネック特定の際に活用してください。「レスポンスタイムを追跡する」「API パフォーマンスを監視する」「遅延を分析する」といった表現で呼び出せます。