

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 의 버전 1과 버전 2 간의 DynamoDB 매핑 API 차이점 AWS SDK for Java
<a name="ddb-mapping"></a>

DynamoDB 매핑 API는 AWS SDK for Java의 버전 1과 버전 2 간에 크게 변경되었습니다. 버전 1에서는 `DynamoDBMapper`를 사용하여 Java POJO를 작업합니다. 버전 2에서는 업데이트된 메서드 이름, 향상된 스키마 정의 옵션 및 향상된 유형 안전과 함께 `DynamoDbEnhancedClient`를 사용합니다.

주요 차이점은 다음과 같습니다.
+ 새 메서드 이름(예: `load` 대신 `getItem`)
+ 명시적 테이블 스키마 만들기
+ 동기식 및 비동기식 작업 모두에 대한 기본 제공 지원
+ 비어 있는 문자열 및 구성 처리 방법 변경

이 섹션에서는 v1 `DynamoDBMapper`에서 v2 `DynamoDbEnhancedClient`로 전환하는 데 도움이 되는 매핑 API 변경 사항, 주석 차이, 구성 업데이트 및 마이그레이션 안내를 다룹니다.

**Contents**
+ [SDK for Java의 버전 1에서 버전 2로의 매핑 라이브러리에 대한 개괄적인 변경 사항](dynamodb-mapping-high-level.md)
  + [종속성 차이 가져오기](dynamodb-mapping-high-level.md#dynamodb-mapping-deps)
+ [SDK for Java 버전 1과 버전 2 간의 DynamoDB 매핑 API 변경 사항](dynamodb-mapping-api-changes.md)
  + [클라이언트 만들기](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-client)
  + [DynamoDB 테이블/인덱스에 대한 매핑 설정](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-mapping)
  + [테이블 작업](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-tobleops)
  + [클래스 및 속성 매핑](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas)
    + [bean 주석](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos)
    + [V2 추가 주석](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos-v2-addnl)
  + [구성](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration)
    + [작업별 구성](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration-per-op)
  + [조건](dynamodb-mapping-api-changes.md#dynamodb-mapping-conditionals)
  + [유형 변환](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv)
    + [기본 변환기](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-defaults)
    + [속성에 대한 사용자 지정 변환기 설정](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-anno)
    + [유형 변환기 팩토리 또는 공급자 추가](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-factory)
+ [SDK for Java 버전 1과 버전 2 간의 문자열 처리 차이점](dynamodb-migration-string-handling.md)
+ [SDK for Java 버전 1과 버전 2의 낙관적 잠금 차이점](dynamodb-migrate-optimstic-locking.md)
+ [SDK for Java 버전 1과 버전 2 간의 유용한 setter 차이점](dynamodb-migrate-fluent-setters.md)

# SDK for Java의 버전 1에서 버전 2로의 매핑 라이브러리에 대한 개괄적인 변경 사항
<a name="dynamodb-mapping-high-level"></a>

각 라이브러리의 매핑 클라이언트 이름은 V1과 V2에서 다릅니다.
+ V1 - DynamoDBMapper
+ V2 - DynamoDB 향상된 클라이언트

두 라이브러리와 거의 동일한 방식으로 상호 작용합니다. 즉, 매퍼/클라이언트를 인스턴스화한 다음 이러한 항목을 읽고 DynamoDB 테이블에 쓰는 API에 Java POJO를 제공합니다. 또한 두 라이브러리 모두 POJO 클래스에 대한 주석을 제공하여 클라이언트가 POJO를 처리하는 방법을 지시합니다.

V2로 이전할 때 눈에 띄는 차이점은 다음과 같습니다.
+ V2와 V1은 하위 수준 DynamoDB 작업에 서로 다른 메서드 이름을 사용합니다. 예제:    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sdk-for-java/latest/developer-guide/dynamodb-mapping-high-level.html)
+ V2는 테이블 스키마를 정의하고 POJO 테이블에 매핑하는 다양한 방법을 제공합니다. 빌더를 사용하여 코드에서 생성된 스키마 또는 주석 사용 중에서 선택할 수 있습니다. 또한 V2는 변경 및 변경 불가능한 버전의 스키마를 제공합니다.
+ V2에서는 특히 첫 번째 단계 중 하나로 테이블 스키마를 만드는 반면, V1에서는 필요에 따라 주석이 달린 클래스에서 테이블 스키마를 추론합니다.
+ V2는 향상된 클라이언트 API에 [문서 API 클라이언트](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)를 포함하는 반면, V1은 [별도의 API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html)를 사용합니다.
+ 모든 API는 V2의 동기식 및 비동기식 버전에서 사용할 수 있습니다.

V2 향상된 클라이언트에 대한 자세한 내용은 이 가이드의 [DynamoDB 매핑 섹션](dynamodb-enhanced-client.md)을 참조하세요.

## 종속성 차이 가져오기
<a name="dynamodb-mapping-deps"></a>


| V1 | V2 | 
| --- | --- | 
|  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>com.amazonaws</groupId><br />      <artifactId>aws-java-sdk-bom</artifactId><br />      <version>1.X.X</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>com.amazonaws</groupId><br />    <artifactId>aws-java-sdk-dynamodb</artifactId><br />  </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>software.amazon.awssdk</groupId><br />      <artifactId>bom</artifactId><br />      <version>2.X.X*</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>software.amazon.awssdk</groupId><br />    <artifactId>dynamodb-enhanced</artifactId><br />  </dependency><br /></dependencies></pre>  | 

\$1 [최신 버전](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

V1에서는 단일 종속성에 하위 수준 DynamoDB API와 매핑/문서 API가 모두 포함되는 반면, V2에서는 `dynamodb-enhanced` 아티팩트 종속성을 사용하여 매핑/문서 API에 액세스합니다. `dynamodb-enhanced` 모듈에는 하위 수준 `dynamodb` 모듈에 대한 전이적 종속성이 포함되어 있습니다.

# SDK for Java 버전 1과 버전 2 간의 DynamoDB 매핑 API 변경 사항
<a name="dynamodb-mapping-api-changes"></a>

## 클라이언트 만들기
<a name="dynamodb-mapping-api-changes-client"></a>


****  

| 사용 사례: | V1 | V2 | 
| --- | --- | --- | 
|   일반 인스턴스화  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard()<br />    .withCredentials(credentialsProvider)<br />    .withRegion(Regions.US_EAST_1)<br />    .build();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbClient standardClient = DynamoDbClient.builder()<br />    .credentialsProvider(ProfileCredentialsProvider.create())<br />    .region(Region.US_EAST_1)<br />    .build();<br />DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .build();</pre>  | 
|   최소 인스턴스화  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();</pre>  | 
|   속성 변환기 사용\$1  |  <pre>DynamoDBMapper mapper = new DynamoDBMapper(standardClient, <br />                        attributeTransformerInstance);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .extensions(extensionAInstance, extensionBInstance)<br />    .build();</pre>  | 

\$1V2의 확장은 대략 V1의 속성 변환기에 해당합니다. 이 [확장 프로그램을 사용하여 DynamoDB 향상된 클라이언트 작업 사용자 지정](ddb-en-client-extensions.md) 섹션에는 V2의 확장에 대한 자세한 내용이 포함되어 있습니다.

## DynamoDB 테이블/인덱스에 대한 매핑 설정
<a name="dynamodb-mapping-api-changes-mapping"></a>

V1에서는 bean 주석을 통해 DynamoDB 테이블 이름을 지정합니다. V2에서는 팩토리 메서드인 `table()`이 원격 DynamoDB 테이블을 나타내는 `DynamoDbTable`의 인스턴스를 생성합니다. `table()` 메서드의 첫 번째 파라미터는 DynamoDB 테이블 이름입니다.


****  

| 사용 사례: | V1 | V2 | 
| --- | --- | --- | 
|   Java POJO 클래스를 DynamoDB 테이블에 매핑  |  <pre>@DynamoDBTable(tableName ="Customer")<br />public class Customer {<br />  ...<br />}</pre>  |  <pre>DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer",<br />    TableSchema.fromBean(Customer.class));</pre>  | 
|   DynamoDB 보조 인덱스에 매핑  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) [ V1 `query` 메서드](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html#DynamoDBMapper.Methods.query)에 대해 설명하는 DynamoDB 개발자 안내서의 섹션에는 전체 예제가 나와 있습니다.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) 이 안내서의 [보조 인덱스 사용](ddb-en-client-use-secindex.md) 섹션에서는 자세한 내용을 제공합니다.  | 

## 테이블 작업
<a name="dynamodb-mapping-api-changes-tobleops"></a>

이 섹션에서는 작업 API를 설명하며, 이는 대부분의 표준 사용 사례에 대한 V1과 V2 간의 차이점이 포함됩니다.

V2에서는 단일 테이블과 관련된 모든 작업이 향상된 클라이언트가 아닌 `DynamoDbTable` 인스턴스에서 직접적으로 호출됩니다. 향상된 클라이언트에는 여러 테이블을 대상으로 지정할 수 있는 메서드가 포함되어 있습니다.

아래 *테이블 작업*이라는 테이블에서 POJO 인스턴스를 `item` 또는 `customer1` 등의 특정 유형이라고 합니다. V2 예제의 경우 이름이 `table`인 인스턴스는 `DynamoDbTable` 인스턴스에 대한 참조를 반환하는 `enhancedClient.table()`을 이전에 직접적으로 호출한 결과입니다.

대부분의 V2 작업은 표시되지 않은 경우에도 유용한 소비자 패턴으로 직접 호출할 수 있습니다. 예:

```
Customer customer = table.getItem(r → r.key(key));
  or
Customer customer = table.getItem(r → r.key(k -> k.partitionValue("id").sortValue("email")))
```

V1 작업의 경우 *테이블 작업*(아래)에는 모든 오버로드된 양식이 아닌 일반적으로 사용되는 양식 중 일부가 포함됩니다. 예를 들어 `load()` 메서드에는 다음과 같은 오버로드가 있습니다.

```
mapper.load(Customer.class, hashKey)
mapper.load(Customer.class, hashKey, rangeKey)
mapper.load(Customer.class, hashKey, config)
mapper.load(Customer.class, hashKey, rangeKey, config)
mapper.load(item)
mapper.load(item, config)
```

*테이블 작업*(아래)은 일반적으로 사용되는 양식을 보여줍니다.

```
mapper.load(item)
mapper.load(item, config)
```


**테이블 작업**  

| 사용 사례: | V1 | V2 | 
| --- | --- | --- | 
|  DynamoDB 테이블에 Java POJO 쓰기 **DynamoDB 작업:** `PutItem`, `UpdateItem`   |  <pre>mapper.save(item)<br />mapper.save(item, config)<br />mapper.save(item, saveExpression, config)</pre> V1에서 `DynamoDBMapperConfig.SaveBehavior` 및 주석은 직접적으로 호출할 하위 수준 DynamoDB 메서드를 결정합니다. 일반적으로 `UpdateItem`은 `SaveBehavior.CLOBBER` 및 `SaveBehavior.PUT` 코드를 사용할 때를 제외하고 직접적으로 호출됩니다. 자동 생성된 키는 특별한 사용 사례이며 경우에 따라 `PutItem` 및 `UpdateItem`이 모두 사용됩니다.  |  <pre>table.putItem(putItemRequest)<br />table.putItem(item)<br />table.putItemWithResponse(item) //Returns metadata.<br /><br />updateItem(updateItemRequest)<br />table.updateItem(item)<br />table.updateItemWithResponse(item) //Returns metadata.</pre>  | 
|  DynamoDB 테이블에서 Java POJO로의 항목 읽기 **DynamoDB 작업:** `GetItem`  |  <pre>mapper.load(item)<br />mapper.load(item, config)</pre>  |  <pre>table.getItem(getItemRequest)<br />table.getItem(item)<br />table.getItem(key)<br />table.getItemWithResponse(key) //Returns POJO with metadata.</pre>  | 
|  DynamoDB 테이블에서 항목 삭제 **DynamoDB 작업:** `DeleteItem`  |  <pre>mapper.delete(item, deleteExpression, config)</pre>  |  <pre>table.deleteItem(deleteItemRequest)<br />table.deleteItem(item)<br />table.deleteItem(key)</pre>  | 
|  DynamoDB 테이블 또는 보조 인덱스 쿼리 및 페이지 매김 목록 반환 **DynamoDB 작업:** `Query`  |  <pre>mapper.query(Customer.class, queryExpression)<br />mapper.query(Customer.class, queryExpression, <br />                             mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> 동기식 응답에서 반환된 `PageIterable.stream()`(지연 로딩) 및 비동기식 응답에서 반환된 `PagePublisher.subscribe()` 사용  | 
|  DynamoDB 테이블 또는 보조 인덱스 쿼리 및 목록 반환 **DynamoDB 작업:** `Query`  |  <pre>mapper.queryPage(Customer.class, queryExpression)<br />mapper.queryPage(Customer.class, queryExpression, <br />                                 mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> 동기식 응답에서 반환된 `PageIterable.items()`(지연 로딩) 및 비동기식 응답에서 반환된 `PagePublisher.items.subscribe()` 사용  | 
|  DynamoDB 테이블 또는 보조 인덱스 스캔 및 페이지 매김 목록 반환 **DynamoDB 작업:** `Scan`  |  <pre>mapper.scan(Customer.class, scanExpression)<br />mapper.scan(Customer.class, scanExpression, <br />                            mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> 동기식 응답에서 반환된 `PageIterable.stream()`(지연 로딩) 및 비동기식 응답에서 반환된 `PagePublisher.subscribe()` 사용  | 
|  DynamoDB 테이블 또는 보조 인덱스 스캔 및 목록 반환 **DynamoDB 작업:** `Scan`  |  <pre>mapper.scanPage(Customer.class, scanExpression)<br />mapper.scanPage(Customer.class, scanExpression, <br />                                mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> 동기식 응답에서 반환된 `PageIterable.items()`(지연 로딩) 및 비동기식 응답에서 반환된 `PagePublisher.items.subscribe()` 사용  | 
|  배치의 여러 테이블에서 여러 항목 읽기 **DynamoDB 작업:** `BatchGetItem`  |  <pre>mapper.batchLoad(Arrays.asList(customer1, <br />                               customer2, <br />                               book1))<br />mapper.batchLoad(itemsToGet) <br />           // itemsToGet: Map<Class<?>, List<KeyPair>></pre>  |  <pre>enhancedClient.batchGetItem(batchGetItemRequest)<br /><br />enhancedClient.batchGetItem(r -> r.readBatches(<br />    ReadBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build(),<br />    ReadBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build()))<br /><br />// Iterate over pages with lazy loading or over all items <br />   from the same table.</pre>  | 
|  배치의 여러 테이블에 여러 항목 쓰기 **DynamoDB 작업:** `BatchWriteItem`  |  <pre>mapper.batchSave(Arrays.asList(customer1, <br />                               customer2, <br />                               book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(batchWriteItemRequest)<br /><br />enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addPutItem(item2)<br />             .build()))</pre>  | 
|  배치의 여러 테이블에서 여러 항목 삭제 **DynamoDB 작업:** `BatchWriteItem`  |  <pre>mapper.batchDelete(Arrays.asList(customer1, <br />                                 customer2, <br />                                 book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addDeleteItem(item1key)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  배치에서 여러 항목 쓰기/삭제 **DynamoDB 작업:** `BatchWriteItem`  |  <pre>mapper.batchWrite(Arrays.asList(customer1, book1), <br />                  Arrays.asList(customer2)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  트랜잭션 쓰기 수행 **DynamoDB 작업:** `TransactWriteItems`  |  <pre>mapper.transactionWrite(transactionWriteRequest)</pre>  |  <pre>enhancedClient.transactWriteItems(transasctWriteItemsRequest)</pre>  | 
|  트랜잭션 읽기 수행 **DynamoDB 작업:** `TransactGetItems`  |  <pre>mapper.transactionLoad(transactionLoadRequest)</pre>  |  <pre>enhancedClient.transactGetItems(transactGetItemsRequest) </pre>  | 
|  쿼리의 일치하는 항목 수 가져오기 **DynamoDB 작업:** `Select.COUNT`로 `Query`  |  <pre>mapper.count(Customer.class, queryExpression)</pre>  |  <pre>// Get the count from query results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.query(QueryEnhancedRequest.builder()<br />        .queryConditional(queryConditional)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.query(QueryEnhancedRequest.builder()<br />                .queryConditional(queryConditional)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  스캔의 일치하는 항목 수 가져오기 **DynamoDB 작업:** `Select.COUNT`로 `Scan`  |  <pre>mapper.count(Customer.class, scanExpression)</pre>  |  <pre>// Get the count from scan results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.scan(ScanEnhancedRequest.builder()<br />        .filterExpression(filterExpression)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.scan(ScanEnhancedRequest.builder()<br />                .filterExpression(filterExpression)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  DynamoDB에서 POJO 클래스에 해당하는 테이블 만들기 **DynamoDB 작업:** `CreateTable`  |  <pre>mapper.generateCreateTableRequest(Customer.class)</pre> 이전 문은 하위 수준 테이블 만들기 요청을 생성합니다. 사용자는 DynamoDB 클라이언트에서 `createTable`을 직접적으로 호출해야 합니다.  |  <pre>table.createTable(createTableRequest)<br /><br />table.createTable(r -> r.provisionedThroughput(defaultThroughput())<br />    .globalSecondaryIndices(<br />        EnhancedGlobalSecondaryIndex.builder()<br />            .indexName("gsi_1")<br />            .projection(p -> p.projectionType(ProjectionType.ALL))<br />            .provisionedThroughput(defaultThroughput())<br />            .build()));</pre>  | 
|  DynamoDB에서 병렬 스캔 수행 **DynamoDB 작업:** `Segment` 및 `TotalSegments` 파라미터로 `Scan`  |  <pre>mapper.parallelScan(Customer.class, <br />                    scanExpression, <br />                    numTotalSegments)</pre>  |  사용자는 작업자 스레드를 처리하고 각 세그먼트에 대해 `scan`을 직접적으로 호출해야 합니다. <pre>table.scan(r -> r.segment(0).totalSegments(5))</pre>  | 
|  Amazon S3를 DynamoDB와 통합하여 지능형 S3 링크 저장  |  <pre>mapper.createS3Link(bucket, key)<br />mapper.getS3ClientCache()</pre>  |  Amazon S3와 DynamoDB를 통합하므로 지원되지 않습니다.  | 

## 클래스 및 속성 매핑
<a name="dynamodb-mapping-schemas"></a>

V1과 V2 모두에서 bean 스타일 주석을 사용하여 클래스를 테이블에 매핑합니다. V2는 변경 불가능한 클래스 작업 등 특정 사용 사례에 대한 [스키마를 정의하는 다른 방법](ddb-en-client-adv-features.md#ddb-en-client-adv-features-schm-overview)도 제공합니다.

### bean 주석
<a name="dynamodb-mapping-schemas-annos"></a>

다음 테이블에는 V1 및 V2에 사용되는 특정 사용 사례별로 동등한 bean 주석이 나와 있습니다. `Customer` 클래스 시나리오는 파라미터를 설명하는 데 사용됩니다.

V2의 주석, 클래스, 열거는 Camel 대문자 규칙을 따르고 ‘DynamoDB’가 아닌 ‘DynamoDb’를 사용합니다.


| 사용 사례: | V1 | V2 | 
| --- | --- | --- | 
| 클래스를 테이블에 매핑 |  <pre>@DynamoDBTable (tableName ="CustomerTable")</pre>  | <pre>@DynamoDbBean<br />@DynamoDbBean(converterProviders = {...})</pre>테이블 이름은 DynamoDbEnhancedClient\$1table() 메서드를 직접적으로 호출할 때 정의됩니다. | 
| 클래스 멤버를 테이블 속성으로 지정  |  <pre>@DynamoDBAttribute(attributeName = "customerName")</pre>  |  <pre>@DynamoDbAttribute("customerName") </pre>  | 
| 클래스 멤버를 해시/파티션 키로 지정 |  <pre>@DynamoDBHashKey </pre>  |  <pre>@DynamoDbPartitionKey</pre>  | 
| 클래스 멤버를 범위/정렬 키로 지정 |  <pre>@DynamoDBRangeKey </pre>  |  <pre>@DynamoDbSortKey </pre>  | 
| 클래스 멤버를 보조 인덱스 해시/파티션 키로 지정 |  <pre>@DynamoDBIndexHashKey </pre>  |  <pre>@DynamoDbSecondaryPartitionKey </pre>  | 
| 클래스 멤버를 보조 인덱스 범위/정렬 키로 지정 |  <pre>@DynamoDBIndexRangeKey </pre>  |  <pre>@DynamoDbSecondarySortKey </pre>  | 
| 테이블에 매핑할 때 이 클래스 멤버 무시 |  <pre>@DynamoDBIgnore </pre>  |  <pre>@DynamoDbIgnore</pre>  | 
| 클래스 멤버를 자동 생성된 UUID 키 속성으로 지정 |  <pre>@DynamoDBAutoGeneratedKey</pre>  |  <pre>@DynamoDbAutoGeneratedUuid </pre> 이를 제공하는 확장 프로그램은 기본적으로 로드되지 않으므로 클라이언트 빌더에 확장 프로그램을 추가해야 합니다.  | 
| 클래스 멤버를 자동 생성된 타임스탬프 속성으로 지정 |  <pre>@DynamoDBAutoGeneratedTimestamp</pre>  |  <pre>@DynamoDbAutoGeneratedTimestampAttribute</pre> 이를 제공하는 확장 프로그램은 기본적으로 로드되지 않으므로 클라이언트 빌더에 확장 프로그램을 추가해야 합니다.  | 
| 클래스 멤버를 자동 증분 버전 속성으로 지정 |  <pre>@DynamoDBVersionAttribute</pre>  |  <pre>@DynamoDbVersionAttribute</pre> 이를 제공하는 확장 프로그램은 자동으로 로드됩니다.  | 
| 클래스 멤버를 사용자 지정 변환이 필요한 것으로 지정 |  <pre>@DynamoDBTypeConverted</pre>  |  <pre>@DynamoDbConvertedBy</pre>  | 
| 다른 속성 유형으로 저장할 클래스 멤버 지정 |  <pre>@DynamoDBTyped(<DynamoDBAttributeType>)</pre>  |  `AttributeConverter` 구현을 사용합니다. V2는 일반적인 Java 유형을 위한 많은 기본 제공 변환기를 지원합니다. 자체 사용자 지정 `AttributeConverter` 또는 `AttributeConverterProvider`를 구현할 수도 있습니다. 이 설명서의 [제어 속성 변환](ddb-en-client-adv-features-conversion.md) 섹션을 참조하세요.  | 
| DynamoDB 문서(JSON 형식 문서) 또는 하위 문서로 직렬화할 수 있는 클래스 지정  |  <pre>@DynamoDBDocument</pre>  | 향상된 문서 API 사용 다음 리소스를 참조하세요.[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) | 

### V2 추가 주석
<a name="dynamodb-mapping-schemas-annos-v2-addnl"></a>


| 사용 사례: | V1 | V2 | 
| --- | --- | --- | 
| Java 값이 null인 경우 클래스 멤버를 null 속성으로 저장하지 않도록 지정 | 해당 사항 없음 |  <pre>@DynamoDbIgnoreNulls</pre>  | 
| 모든 속성이 null인 경우 클래스 멤버를 비어 있는 객체로 지정 | 해당 사항 없음 |  <pre>@DynamoDbPreserveEmptyObject</pre>  | 
| 클래스 멤버에 대한 특별 업데이트 작업 지정 | 해당 사항 없음 |  <pre>@DynamoDbUpdateBehavior</pre>  | 
| 변경할 수 없는 클래스 지정 | 해당 사항 없음 |  <pre>@DynamoDbImmutable</pre>  | 
| 클래스 멤버를 자동 증분 카운터 속성으로 지정 | 해당 사항 없음 |  <pre>@DynamoDbAtomicCounter</pre> 이 기능을 제공하는 확장 프로그램은 자동으로 로드됩니다.  | 

## 구성
<a name="dynamodb-mapping-configuration"></a>

V1에서는 일반적으로 `DynamoDBMapperConfig`의 인스턴스를 사용하여 특정 동작을 제어합니다. 매퍼를 만들거나 요청할 때 구성 객체를 제공할 수 있습니다. V2에서 구성은 작업에 대한 요청 객체에 따라 다릅니다.


| 사용 사례: | V1 | V1의 기본값 | V2 | 
| --- | --- | --- | --- | 
|  |  <pre>DynamoDBMapperConfig.builder()</pre>  |  |  | 
| 배치 로드/쓰기 재시도 전략 |  <pre>  .withBatchLoadRetryStrategy(loadRetryStrategy)</pre> <pre>  .withBatchWriteRetryStrategy(writeRetryStrategy)</pre>  | 실패한 항목 재시도 | 기본 DynamoDBClient에서 재시도 전략을 구성합니다. 이 설명서의 [에서 재시도 동작 구성 AWS SDK for Java 2.x](retry-strategy.md) 섹션을 참조하세요. | 
| 일관된 읽기 |  <pre>  .withConsistentReads(CONSISTENT)</pre>  | EVENTUAL | 기본적으로 일관된 읽기는 읽기 작업에 대해 false입니다. 요청 객체에서 .consistentRead(true)로 재정의합니다. | 
| 마샬러/언마샬러 세트가 포함된 변환 스키마 |  <pre>  .withConversionSchema(conversionSchema)</pre> 정적 구현에서는 구버전과 이전 버전과의 호환성을 제공합니다.  | V2\$1COMPATIBLE | 해당 사항 없음. 이는 DynamoDB(V1)의 최신 버전이 데이터 형식을 저장한 방식을 나타내는 레거시 기능이며, 이 동작은 향상된 클라이언트에서 유지되지 않습니다. DynamoDB V1의 동작 예제는 부울을 부울 대신 숫자로 저장합니다. | 
| 테이블 이름 |  <pre>  .withObjectTableNameResolver()<br />  .withTableNameOverride() <br />  .withTableNameResolver()</pre> 정적 구현에서 구버전과 이전 버전과의 호환성 제공  | 클래스에서 주석 또는 추측 사용 |  테이블 이름은 `DynamoDbEnhancedClient#table()` 메서드를 직접적으로 호출할 때 정의됩니다.  | 
| 페이지 매김 로드 전략 |  <pre>  .withPaginationLoadingStrategy(strategy)</pre>  옵션은 LAZY\$1`LOADING`, `EAGER_LOADING` 또는 `ITERATION_ONLY`입니다.  | LAZY\$1LOADING |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html)  | 
| 지표 수집 요청 |  <pre>  .withRequestMetricCollector(collector)</pre>  | null | 표준 DynamoDB 클라이언트를 구축할 때 ClientOverrideConfiguration에서 metricPublisher()를 사용합니다. | 
| 동작 저장 |  <pre>  .withSaveBehavior(SaveBehavior.CLOBBER) </pre> 옵션은 `UPDATE`, `CLOBBER`, `PUT`, `APPEND_SET`, `UPDATE_SKIP_NULL_ATTRIBUTES`입니다.  | UPDATE |  V2에서는 `putItem()` 또는 `updateItem()`을 명시적으로 직접 호출합니다. `CLOBBER or PUT`: v 2의 해당 작업은 `putItem()`을 직접적으로 호출합니다. 특정 `CLOBBER` 구성은 없습니다. `UPDATE`:에 해당 `updateItem()` `UPDATE_SKIP_NULL_ATTRIBUTES`:에 해당합니다`updateItem()`. 요청 설정 `ignoreNulls` 및 주석/태그 `DynamoDbUpdateBehavior`를 사용하여 업데이트 동작을 제어합니다. `APPEND_SET`: 지원되지 않음:  | 
| 유형 변환기 팩토리 |  <pre>  .withTypeConverterFactory(typeConverterFactory) </pre>  | 표준 유형 변환기 |  bean에 설정하는 수단 <pre>@DynamoDbBean(converterProviders = {ConverterProvider.class, <br />        DefaultAttributeConverterProvider.class})</pre>  | 

### 작업별 구성
<a name="dynamodb-mapping-configuration-per-op"></a>

V1에서 `query()` 등의 일부 작업은 작업에 제출된 ‘표현식’ 객체를 통해 고도로 구성할 수 있습니다. 예제:

```
DynamoDBQueryExpression<Customer> emailBwQueryExpr = new DynamoDBQueryExpression<Customer>()
    .withRangeKeyCondition("Email",
        new Condition()
            .withComparisonOperator(ComparisonOperator.BEGINS_WITH)
            .withAttributeValueList(
                new AttributeValue().withS("my")));

mapper.query(Customer.class, emailBwQueryExpr);
```

V2에서는 구성 객체를 사용하는 대신 빌더를 사용하여 요청 객체에 파라미터를 설정합니다. 예제:

```
QueryEnhancedRequest emailBw = QueryEnhancedRequest.builder()
    .queryConditional(QueryConditional
        .sortBeginsWith(kb -> kb
            .sortValue("my"))).build();

customerTable.query(emailBw);
```

## 조건
<a name="dynamodb-mapping-conditionals"></a>

V2에서 조건부 및 필터링 표현식은 조건과 이름 및 필터 매핑을 캡슐화하는 `Expression` 객체를 사용하여 표현됩니다.


| 사용 사례: | 운영 | V1 | V2 | 
| --- | --- | --- | --- | 
| 예상 속성 조건 | save(), delete(), query(), scan() |  <pre>new DynamoDBSaveExpression()<br />  .withExpected(Collections.singletonMap(<br />      "otherAttribute", new ExpectedAttributeValue(false)))<br />  .withConditionalOperator(ConditionalOperator.AND);</pre>  | 지원 종료되며 대신 ConditionExpression을 사용합니다. | 
| 조건 표현식 | delete() |  <pre>deleteExpression.setConditionExpression("zipcode = :zipcode")<br />deleteExpression.setExpressionAttributeValues(...)<br /></pre>  |  <pre>Expression conditionExpression =<br />    Expression.builder()<br />        .expression("#key = :value OR #key1 = :value1")<br />        .putExpressionName("#key", "attribute")<br />        .putExpressionName("#key1", "attribute3")<br />        .putExpressionValue(":value", AttributeValues.stringValue("wrong"))<br />        .putExpressionValue(":value1", AttributeValues.stringValue("three"))<br />        .build();<br /><br />DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()<br />         .conditionExpression(conditionExpression).build();</pre>  | 
| 필터 표현식 | query(), scan() |  <pre>scanExpression<br />  .withFilterExpression("#statename = :state")<br />  .withExpressionAttributeValues(attributeValueMapBuilder.build())<br />  .withExpressionAttributeNames(attributeNameMapBuilder.build())<br /></pre>  |  <pre>Map<String, AttributeValue> values = singletonMap(":key", stringValue("value"));<br />Expression filterExpression =<br />    Expression.builder()<br />        .expression("name = :key")<br />        .expressionValues(values)<br />        .build();<br />QueryEnhancedRequest request = QueryEnhancedRequest.builder()<br />    .filterExpression(filterExpression).build();<br /></pre>  | 
| 쿼리에 대한 키 조건 표현식 | query() |  <pre>queryExpression.withKeyConditionExpression()</pre>  |  <pre>QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b<br />                .partitionValue("movie01"));<br /><br />QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()<br />                .queryConditional(keyEqual)<br />                .build();</pre>  | 

## 유형 변환
<a name="dynamodb-mapping-type-conv"></a>

### 기본 변환기
<a name="dynamodb-mapping-type-conv-defaults"></a>

V2에서 SDK는 모든 일반 유형에 대한 기본 변환기 세트를 제공합니다. 전반적 공급자 수준과 단일 속성 모두에서 유형 변환기를 변경할 수 있습니다. [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html) API 참조에서 사용 가능한 변환기 목록을 확인할 수 있습니다.

### 속성에 대한 사용자 지정 변환기 설정
<a name="dynamodb-mapping-type-conv-anno"></a>

V1에서는 `@DynamoDBTypeConverted`로 getter 메서드에 주석을 달아 Java 속성 유형과 DynamoDB 속성 유형 간에 변환되는 클래스를 지정할 수 있습니다. 예를 들어 Java `Currency` 유형과 DynamoDB 문자열 간에 변환되는 `CurrencyFormatConverter`는 다음 코드 조각과 같이 적용할 수 있습니다.

```
@DynamoDBTypeConverted(converter = CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

이전 코드 조각과 동일한 V2가 아래에 나와 있습니다.

```
@DynamoDbConvertedBy(CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

**참고**  
V1에서는 속성 자체, 유형 또는 사용자 정의 주석에 주석을 적용할 수 있으며, V2는 주석을 getter에만 적용할 수 있도록 지원합니다.

### 유형 변환기 팩토리 또는 공급자 추가
<a name="dynamodb-mapping-type-conv-factory"></a>

V1에서는 고유한 유형 변환기 세트를 제공하거나 구성에 유형 변환기 팩토리를 추가하여 관심 있는 유형을 재정의할 수 있습니다. 유형 변환기 팩토리는 `DynamoDBTypeConverterFactory`를 확장하며, 기본 세트에 대한 참조를 가져와서 확장하면 재정의가 수행됩니다. 다음은 이 작업을 수행하는 방법을 보여주는 Java 코드 조각입니다.

```
DynamoDBTypeConverterFactory typeConverterFactory =
    DynamoDBTypeConverterFactory.standard().override()
        .with(String.class, CustomBoolean.class, new DynamoDBTypeConverter<String, CustomBoolean>() {
            @Override
            public String convert(CustomBoolean bool) {
                return String.valueOf(bool.getValue());
            }
            @Override
            public CustomBoolean unconvert(String string) {
                return new CustomBoolean(Boolean.valueOf(string));
            }}).build();
DynamoDBMapperConfig config =
    DynamoDBMapperConfig.builder()
        .withTypeConverterFactory(typeConverterFactory)
        .build();
DynamoDBMapper mapperWithTypeConverterFactory = new DynamoDBMapper(dynamo, config);
```

V2는 `@DynamoDbBean` 주석을 통해 유사한 기능을 제공합니다. 단일 `AttributeConverterProvider` 또는 순서대로 정리된 `AttributeConverterProvider`의 체인을 제공할 수 있습니다. 자체 속성 변환기 공급자 체인을 제공하는 경우 기본 변환기 공급자가 재정의되고 해당 속성 변환기를 사용하려면 체인에 포함되어야 함을 참고하시기 바랍니다.

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {
  ...
}
```

이 안내서의 [속성 변환](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example) 섹션에는 V2에 대한 전체 예제가 포함되어 있습니다.

# SDK for Java 버전 1과 버전 2 간의 문자열 처리 차이점
<a name="dynamodb-migration-string-handling"></a>

V1과 V2는 DynamoDB로 데이터를 전송할 때 비어 있는 문자열을 다르게 처리합니다.
+ **V1**: DynamoDB로 전송하기 전에 비어 있는 문자열을 null 값으로 변환합니다(속성 없음).
+ **V2**: 비어 있는 문자열을 DynamoDB에 실제 비어 있는 문자열 값으로 전송합니다.

**중요**  
V2로 마이그레이션한 후 DynamoDB에 비어 있는 문자열을 저장하지 않으려면 사용자 지정 변환기를 구현해야 합니다. 사용자 지정 변환기가 없으면 V2는 비어 있는 문자열을 DynamoDB 항목에 실제 비어 있는 문자열 속성으로 저장합니다. 이는 이러한 속성을 완전히 생략하는 V1의 동작과 다릅니다.

**Example 비어 있는 문자열 속성을 null로 변환하는 V2용 사용자 지정 변환기**  

```
/**
 * Custom converter that maintains V1 behavior by converting empty strings to null values
 * when writing to DynamoDB, ensuring compatibility with existing data. No attribute will be saved to DynamoDB.
 */
public class NullifyEmptyStringConverter implements AttributeConverter<String> {
    @Override
    public AttributeValue transformFrom(String value) {
        if (value == null || value.isEmpty()) {
            return AttributeValue.builder().nul(true).build();
        }
        return AttributeValue.builder().s(value).build();
    }

    @Override
    public String transformTo(AttributeValue attributeValue) {
        if (attributeValue.nul()) {
            return null;
        }
        return attributeValue.s();
    }

    @Override
    public EnhancedType<String> type() {
        return EnhancedType.of(String.class);
    }

    @Override
    public AttributeValueType attributeValueType() {
        return AttributeValueType.S;
    }
}

// V2 usage:
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(NullifyEmptyStringConverter.class)
    public String getName() {
        return name;
    }
}
```



# SDK for Java 버전 1과 버전 2의 낙관적 잠금 차이점
<a name="dynamodb-migrate-optimstic-locking"></a>

V1과 V2 모두 bean 클래스에 하나의 속성을 표시하여 버전 번호를 저장하는 속성 주석으로 낙관적 잠금을 구현합니다.


**낙관적 잠금 동작의 차이점**  

|  | V1 | V2 | 
| --- | --- | --- | 
| bean 클래스 주석 | @DynamoDBVersionAttribute | @DynamoDbVersionAttribute(V2는 소문자 ‘b’ 사용) | 
| 초기 저장 | 버전 번호 속성은 1로 설정됩니다. |  `@DynamoDbVersionAttribute(startAt = X)`로 설정된 버전 속성의 시작 값입니다. 기본값은 0입니다.  | 
| 업데이트 | 조건부 확인에서 업데이트 중인 객체의 버전 번호가 데이터베이스의 번호와 일치하는지 확인하면 버전 번호 속성이 1씩 증가합니다. |  조건부 확인에서 업데이트 중인 객체의 버전 번호가 데이터베이스의 번호와 일치하는지 확인하면 버전 번호 속성이 증분합니다. `@DynamoDbVersionAttribute(incrementBy = X)`로 설정된 `incrementBy` 옵션에 따라 증분하는 버전 번호 속성입니다. 기본값은 1입니다.  | 
| Delete | DynamoDBMapper는 삭제 중인 객체의 버전 번호가 데이터베이스의 버전 번호와 일치하는지 조건부 확인을 추가합니다. |  V2는 삭제 작업에 대한 조건을 자동으로 추가하지 않습니다. 삭제 동작을 제어하려면 조건 표현식을 수동으로 추가해야 합니다. 다음 예제에서 `recordVersion`은 bean의 버전 속성입니다. <pre>// 1. Read the item and get its current version.<br />Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build());<br />AttributeValue currentVersion = item.getRecordVersion();<br /><br />// 2. Create conditional delete with the `currentVersion` value.<br />DeleteItemEnhancedRequest deleteItemRequest =<br />    DeleteItemEnhancedRequest.builder()<br />       .key(KEY)<br />       .conditionExpression(Expression.builder()<br />           .expression("recordVersion = :current_version_value")<br />           .putExpressionValue(":current_version_value", currentVersion)<br />           .build()).build();<br /><br />customerTable.deleteItem(deleteItemRequest);</pre>  | 
| 조건 확인을 사용한 트랜잭션 쓰기 | addConditionCheck 메서드에서 @DynamoDBVersionAttribute로 주석이 달린 bean 클래스는 사용할 수 없습니다. | transactWriteItems 요청에 대해 addConditionCheck 빌더 메서드의 @DynamoDbVersionAttribute 주석과 함께 bean 클래스를 사용할 수 있습니다. | 
| 비활성화 | 낙관적 잠금은  DynamoDBMapperConfig.SaveBehavior 열거 값을 UPDATE에서 CLOBBER로 변경하면 사용 해제할 수 있습니다. |  `@DynamoDbVersionAttribute` 주석을 사용하지 마세요.  | 

# SDK for Java 버전 1과 버전 2 간의 유용한 setter 차이점
<a name="dynamodb-migrate-fluent-setters"></a>

V1용 DynamoDB 매핑 API에서 유용한 setter와 버전 2.30.29 이후 V2에서 POJO를 사용할 수 있습니다.

예를 들어 다음 POJO는 `setName` 메서드에서 `Customer` 인스턴스를 반환합니다.

```
// V1

@DynamoDBTable(tableName ="Customer")
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){
     this.name = name;
     return this;
  }
}
```

그러나 2.30.29 이전의 V2 버전을 사용하는 경우 `setName`은 `name` 값이 `null`인 `Customer` 인스턴스를 반환합니다.

```
// V2 prior to version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Bug: returns this instance with a `name` value of `null`.
  }
}
```

```
// Available in V2 since version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Returns this instance for method chaining with the `name` value set.
  }
}
```