

# Java 1.x: DynamoDBMapper
<a name="DynamoDBMapper"></a>

**참고**  
SDK for Java에는 1.x와 2.x의 두 가지 버전이 있습니다. 1.x의 경우 2024년 1월 12일에 지원 종료가 [발표되었습니다](https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-java-v1-x-on-december-31-2025/). 2025년 12월 31일에 지원이 종료될 예정입니다. 새 개발의 경우 2.x를 사용하는 것이 좋습니다.

AWS SDK for Java에서는 클라이언트 측 클래스를 Amazon DynamoDB 테이블로 매핑할 수 있는 `DynamoDBMapper` 클래스를 제공합니다. `DynamoDBMapper`를 사용하려면 코드에서 DynamoDB 테이블의 항목과 해당하는 객체 인스턴스 간의 관계를 정의합니다. `DynamoDBMapper` 클래스를 사용하면 항목에 대한 다양한 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행하고 테이블에 대한 쿼리 및 스캔을 실행할 수 있습니다.

**Topics**
+ [DynamoDBMapper 클래스](DynamoDBMapper.Methods.md)
+ [Java용 DynamoDBMapper에서 지원되는 데이터 형식](DynamoDBMapper.DataTypes.md)
+ [DynamoDB에 사용되는 Java 주석](DynamoDBMapper.Annotations.md)
+ [DynamoDBMapper의 구성 설정(선택 사항)](DynamoDBMapper.OptionalConfig.md)
+ [DynamoDB 및 버전 번호를 이용한 낙관적 잠금](DynamoDBMapper.OptimisticLocking.md)
+ [DynamoDB에서 임의 데이터 매핑](DynamoDBMapper.ArbitraryDataMapping.md)
+ [DynamoDBMapper 예제](DynamoDBMapper.Examples.md)

**참고**  
`DynamoDBMapper` 클래스는 테이블 생성, 업데이트 또는 삭제를 허용하지 않습니다. 이러한 작업을 위해서는 대신 하위 수준 SDK for Java 인터페이스를 사용해야 합니다.

SDK for Java는 클래스를 테이블로 매핑할 수 있도록 일련의 주석 유형을 제공합니다. 예를 들어, `ProductCatalog` 테이블의 `Id`가 파티션 키인 경우 

```
ProductCatalog(Id, ...)
```

아래 Java 코드와 같이 클라이언트 애플리케이션의 클래스를 `ProductCatalog` 테이블로 매핑할 수 있습니다. 이 코드는 `CatalogItem`이라는 POJO(Plain Old Java Object)를 정의합니다. 여기서는 주석을 사용하여 객체 필드를 DynamoDB 속성 이름에 매핑합니다.

**Example**  

```
package com.amazonaws.codesamples;

import java.util.Set;

import software.amazon.dynamodb.datamodeling.DynamoDBAttribute;
import software.amazon.dynamodb.datamodeling.DynamoDBHashKey;
import software.amazon.dynamodb.datamodeling.DynamoDBIgnore;
import software.amazon.dynamodb.datamodeling.DynamoDBTable;

@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {

    private Integer id;
    private String title;
    private String ISBN;
    private Set<String> bookAuthors;
    private String someProp;

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id; }
    public void setId(Integer id) {this.id = id; }

    @DynamoDBAttribute(attributeName="Title")
    public String getTitle() {return title; }
    public void setTitle(String title) { this.title = title; }

    @DynamoDBAttribute(attributeName="ISBN")
    public String getISBN() { return ISBN; }
    public void setISBN(String ISBN) { this.ISBN = ISBN; }

    @DynamoDBAttribute(attributeName="Authors")
    public Set<String> getBookAuthors() { return bookAuthors; }
    public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; }

    @DynamoDBIgnore
    public String getSomeProp() { return someProp; }
    public void setSomeProp(String someProp) { this.someProp = someProp; }
}
```

위의 코드에서 `@DynamoDBTable` 주석은 `CatalogItem` 클래스를 `ProductCatalog` 테이블로 매핑합니다. 각 클래스 인스턴스는 항목 형태로 이 테이블에 저장할 수 있습니다. 클래스 정의에서 `@DynamoDBHashKey` 주석은 `Id` 속성을 기본 키로 매핑합니다.

기본적으로 클래스 속성은 테이블에서 동일한 이름의 속성으로 매핑됩니다. 예를 들어 `Title` 및 `ISBN` 속성은 테이블에서 동일한 이름의 속성으로 매핑됩니다.

DynamoDB 속성의 이름이 클래스에서 선언된 속성의 이름과 일치하는 경우 `@DynamoDBAttribute` 주석을 선택적으로 사용할 수 있습니다. 이러한 이름이 서로 다르면 이 주석을 `attributeName` 파라미터와 함께 사용하여 이 속성에 대응하는 DynamoDB 속성을 지정합니다.

위 예제에서는 속성 이름이 이전 단계에서 만든 테이블과 정확히 일치하면서 이 가이드의 다른 코드 예제에서도 일관된 속성 이름을 사용할 수 있도록 `@DynamoDBAttribute` 주석이 각 속성에 추가되었습니다.

클래스 정의는 테이블의 어떤 속성에도 매핑되지 않는 속성을 가질 수도 있습니다. `@DynamoDBIgnore` 주석을 추가하여 이러한 속성을 확인할 수 있습니다. 위 예제에서는 `SomeProp` 속성이 `@DynamoDBIgnore` 주석으로 표시되어 있습니다. `CatalogItem` 인스턴스를 테이블에 업로드할 때 `DynamoDBMapper` 인스턴스에는 `SomeProp` 속성이 포함되지 않습니다. 또한 테이블에서 항목을 가져오더라도 매퍼가 이 속성을 반환하지 않습니다.

매핑 클래스를 정의한 후에는 `DynamoDBMapper` 메서드를 사용하여 해당 클래스의 인스턴스를 `Catalog` 테이블의 해당 항목에 쓸 수 있습니다. 다음 코드 예제에서는 이 과정을 보여줍니다.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();

DynamoDBMapper mapper = new DynamoDBMapper(client);

CatalogItem item = new CatalogItem();
item.setId(102);
item.setTitle("Book 102 Title");
item.setISBN("222-2222222222");
item.setBookAuthors(new HashSet<String>(Arrays.asList("Author 1", "Author 2")));
item.setSomeProp("Test");

mapper.save(item);
```

다음 코드 예제에서는 항목을 검색하고 일부 속성에 액세스하는 방법을 보여줍니다.

```
CatalogItem partitionKey = new CatalogItem();

partitionKey.setId(102);
DynamoDBQueryExpression<CatalogItem> queryExpression = new DynamoDBQueryExpression<CatalogItem>()
    .withHashKeyValues(partitionKey);

List<CatalogItem> itemList = mapper.query(CatalogItem.class, queryExpression);

for (int i = 0; i < itemList.size(); i++) {
    System.out.println(itemList.get(i).getTitle());
    System.out.println(itemList.get(i).getBookAuthors());
}
```

`DynamoDBMapper`는 Java에서 DynamoDB 데이터를 사용하는 직관적이고 자연스러운 방법을 제공합니다. 또한 낙관적 잠금, ACID 트랜잭션, 자동 생성된 파티션 키 및 정렬 키 값, 객체 버전 관리 등 기본적인 여러 기능을 제공합니다.

# DynamoDBMapper 클래스
<a name="DynamoDBMapper.Methods"></a>



`DynamoDBMapper` 클래스는 Amazon DynamoDB API의 진입점입니다. DynamoDB 엔드포인트에 액세스하고 여러 테이블의 데이터에 액세스할 수 있습니다. 또한 항목에 대한 다양한 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행하고 테이블에 대한 쿼리 및 스캔을 실행할 수 있습니다. 이 클래스는 DynamoDB를 작업하기 위한 다음과 같은 메서드를 제공합니다.

해당 Javadoc 설명서는 *AWS SDK for Java API 참조*의 [DynamoDBMapper](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html)를 참조하세요.

**Topics**
+ [저장](#DynamoDBMapper.Methods.save)
+ [로드](#DynamoDBMapper.Methods.load)
+ [삭제](#DynamoDBMapper.Methods.delete)
+ [쿼리](#DynamoDBMapper.Methods.query)
+ [queryPage](#DynamoDBMapper.Methods.queryPage)
+ [스캔](#DynamoDBMapper.Methods.scan)
+ [scanPage](#DynamoDBMapper.Methods.scanPage)
+ [parallelScan](#DynamoDBMapper.Methods.parallelScan)
+ [batchSave](#DynamoDBMapper.Methods.batchSave)
+ [batchLoad](#DynamoDBMapper.Methods.batchLoad)
+ [batchDelete](#DynamoDBMapper.Methods.batchDelete)
+ [batchWrite](#DynamoDBMapper.Methods.batchWrite)
+ [transactionWrite](#DynamoDBMapper.Methods.transactionWrite)
+ [transactionLoad](#DynamoDBMapper.Methods.transactionLoad)
+ [count](#DynamoDBMapper.Methods.count)
+ [generateCreateTableRequest](#DynamoDBMapper.Methods.generateCreateTableRequest)
+ [createS3Link](#DynamoDBMapper.Methods.createS3Link)
+ [getS3ClientCache](#DynamoDBMapper.Methods.getS3ClientCache)

## 저장
<a name="DynamoDBMapper.Methods.save"></a>

지정한 객체를 테이블에 저장합니다. 여기서 저장하는 객체가 이 메서드에 유일하게 필요한 파라미터입니다. `DynamoDBMapperConfig` 객체를 사용하여 옵션으로 구성 파라미터를 입력할 수도 있습니다.

동일한 기본 키를 사용하는 항목이 없을 경우에는 이 메서드가 테이블에 새로운 항목을 생성합니다. 그리고, 동일한 기본 키를 사용하는 항목이 있을 경우에는 기존 항목을 업데이트합니다. 파티션 키와 정렬 키가 String 형식이고 `@DynamoDBAutoGeneratedKey`로 주석된 경우 초기화되지 않았으면 랜덤 UUID(Universally Unique Identifier)가 부여됩니다. `@DynamoDBVersionAttribute` 주석이 추가된 버전 필드는 1씩 증가합니다. 또한 버전 필드를 업데이트하거나 키를 생성하는 경우 작업 결과에 따라 전달되는 객체도 업데이트됩니다.

기본적으로 매핑된 클래스 속성에 해당되는 속성만 업데이트됩니다. 항목의 기존 추가 속성은 영향을 받지 않습니다. 하지만 `SaveBehavior.CLOBBER`를 지정할 경우 항목을 강제로 완전히 덮어쓸 수 있습니다.

```
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder()
    .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER).build();
        
mapper.save(item, config);
```

버전 관리를 활성화하면 클라이언트 측 항목 버전과 서버 측 항목 버전이 일치해야 합니다. 하지만 `SaveBehavior.CLOBBER` 옵션을 사용하면 버전이 일치하지 않아도 괜찮습니다. 버전 관리에 대한 자세한 내용은 [DynamoDB 및 버전 번호를 이용한 낙관적 잠금](DynamoDBMapper.OptimisticLocking.md) 섹션을 참조하십시오.

## 로드
<a name="DynamoDBMapper.Methods.load"></a>

테이블에서 항목을 가져옵니다. 검색할 항목의 기본 키를 제공해야 합니다. `DynamoDBMapperConfig` 객체를 사용하여 옵션으로 구성 파라미터를 입력할 수도 있습니다. 예를 들어 아래 Java 문과 같이 이 메서드를 실행하여 최신 항목 값만 가져오려면 옵션으로 strongly consistent read를 요청하면 됩니다.

```
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder()
    .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT).build();

CatalogItem item = mapper.load(CatalogItem.class, item.getId(), config);
```

기본적으로 DynamoDB는 최종적으로 일관된 값을 갖는 항목을 반환하기 때문입니다. DynamoDB의 최종 일관성 모델에 대한 자세한 내용은 [DynamoDB 읽기 일관성](HowItWorks.ReadConsistency.md) 단원을 참조하세요.

## 삭제
<a name="DynamoDBMapper.Methods.delete"></a>

항목을 테이블에서 삭제합니다. 이때는 매핑된 클래스의 객체 인스턴스를 전달해야 합니다.

버전 관리를 활성화하면 클라이언트 측 항목 버전과 서버 측 항목 버전이 일치해야 합니다. 하지만 `SaveBehavior.CLOBBER` 옵션을 사용하면 버전이 일치하지 않아도 괜찮습니다. 버전 관리에 대한 자세한 내용은 [DynamoDB 및 버전 번호를 이용한 낙관적 잠금](DynamoDBMapper.OptimisticLocking.md) 섹션을 참조하십시오.

## 쿼리
<a name="DynamoDBMapper.Methods.query"></a>

테이블 또는 보조 인덱스를 쿼리합니다.

포럼 스레드 회신이 저장되는 `Reply` 테이블이 있는 경우 스레드 제목마다 회신 수가 0개 또는 그 이상이 될 수 있습니다. `Reply` 테이블의 기본 키는 `Id` 및 `ReplyDateTime` 필드로 구성됩니다. 여기에서 `Id`는 파티션 키이고, `ReplyDateTime`은 기본 키의 정렬 키입니다.

```
Reply ( Id, ReplyDateTime, ... )
```

`Reply` 클래스와 DynamoDB의 해당 `Reply` 테이블 간 매핑을 생성한 경우 다음 Java 코드는 `DynamoDBMapper`를 사용하여 특정 스레드 제목에 대한 지난 2주 간 모든 회신을 찾습니다.

**Example**  

```
String forumName = "&DDB;";
String forumSubject = "&DDB; Thread 1";
String partitionKey = forumName + "#" + forumSubject;

long twoWeeksAgoMilli = (new Date()).getTime() - (14L*24L*60L*60L*1000L);
Date twoWeeksAgo = new Date();
twoWeeksAgo.setTime(twoWeeksAgoMilli);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String twoWeeksAgoStr = df.format(twoWeeksAgo);

Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1", new AttributeValue().withS(partitionKey));
eav.put(":v2",new AttributeValue().withS(twoWeeksAgoStr.toString()));

DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>()
    .withKeyConditionExpression("Id = :v1 and ReplyDateTime > :v2")
    .withExpressionAttributeValues(eav);

List<Reply> latestReplies = mapper.query(Reply.class, queryExpression);
```

쿼리 결과 `Reply` 객체 컬렉션이 반환됩니다.

기본적으로 `query` 메서드는 "지연 로딩된(lazy-loaded)" 컬렉션을 반환합니다. 즉, 처음에는 결과 페이지를 하나만 반환하고, 필요에 따라 서비스를 호출하여 다음 페이지를 반환합니다. 일치하는 항목을 모두 가져오려면 `latestReplies` 컬렉션을 반복합니다.

컬렉션에서 `size()` 메서드를 호출하면 정확한 개수를 제공하기 위해 모든 결과가 로드됩니다. 이로 인해 프로비저닝된 처리량이 많이 사용될 수 있으며, 매우 큰 테이블에서는 JVM의 모든 메모리가 소모될 수도 있습니다.

인덱스를 쿼리하려면 먼저 인덱스를 매퍼 클래스로 모델링해야 합니다. `Reply` 테이블에는 *PostedBy-Message-Index*라는 글로벌 보조 인덱스가 있습니다. 이 인덱스의 파티션 키는 `PostedBy`이고, 정렬 키는 `Message`입니다. 이 인덱스에서 항목의 클래스 정의는 다음과 같을 것입니다.

```
@DynamoDBTable(tableName="Reply")
public class PostedByMessage {
    private String postedBy;
    private String message;

    @DynamoDBIndexHashKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "PostedBy")
    public String getPostedBy() { return postedBy; }
    public void setPostedBy(String postedBy) { this.postedBy = postedBy; }

    @DynamoDBIndexRangeKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "Message")
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }

   // Additional properties go here.
}
```

`@DynamoDBTable` 주석은 이 인덱스가 `Reply` 테이블과 연결되어 있음을 나타냅니다. `@DynamoDBIndexHashKey` 주석은 인덱스의 파티션 키(*PostedBy*)를 표시하고, `@DynamoDBIndexRangeKey`는 인덱스의 정렬 키(*Message*)를 표시합니다.

이제 `DynamoDBMapper`를 사용하여 특정 사용자가 게시한 메시지 하위 집합을 검색하는 인덱스 쿼리를 실행할 수 있습니다. 테이블과 인덱스에 충돌하는 매핑이 없고 매핑이 이미 매퍼에서 만들어진 경우에는 인덱스 이름을 지정할 필요가 없습니다. 매퍼는 프라이머리 키와 정렬 키를 기반으로 추론합니다. 다음 코드에서는 글로벌 보조 인덱스를 쿼리합니다. 글로벌 보조 인덱스는 최종적 일관된 읽기는 지원하지만 강력히 일관된 읽기는 지원하지 않으므로 `withConsistentRead(false)`를 지정해야 합니다.

```
HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1",  new AttributeValue().withS("User A"));
eav.put(":v2",  new AttributeValue().withS("DynamoDB"));

DynamoDBQueryExpression<PostedByMessage> queryExpression = new DynamoDBQueryExpression<PostedByMessage>()
    .withIndexName("PostedBy-Message-Index")
    .withConsistentRead(false)
    .withKeyConditionExpression("PostedBy = :v1 and begins_with(Message, :v2)")
    .withExpressionAttributeValues(eav);

List<PostedByMessage> iList =  mapper.query(PostedByMessage.class, queryExpression);
```

쿼리 결과 `PostedByMessage` 객체 컬렉션이 반환됩니다.

## queryPage
<a name="DynamoDBMapper.Methods.queryPage"></a>

테이블 또는 보조 인덱스를 쿼리하고 일치하는 결과를 단일 페이지로 반환합니다. `query` 메서드에서 그랬듯이 이번에도 파티션 키 값을 비롯해 정렬 키 속성에 적용되는 쿼리 필터를 지정해야 합니다. 그러나 `queryPage`는 첫 번째 데이터 "페이지"만 반환합니다. 다시 말해서 1M를 넘지 않는 범위에서 데이터를 반환합니다.

## 스캔
<a name="DynamoDBMapper.Methods.scan"></a>

전체 테이블 또는 보조 인덱스를 스캔합니다. `FilterExpression`를 지정하여 결과 집합을 필터링할 수도 있습니다(선택 사항).

포럼 스레드 회신이 저장되는 `Reply` 테이블이 있는 경우 스레드 제목마다 회신 수가 0개 또는 그 이상이 될 수 있습니다. `Reply` 테이블의 기본 키는 `Id` 및 `ReplyDateTime` 필드로 구성됩니다. 여기에서 `Id`는 파티션 키이고, `ReplyDateTime`은 기본 키의 정렬 키입니다.

```
Reply ( Id, ReplyDateTime, ... )
```

Java 클래스를 `Reply` 테이블로 매핑한 경우 `DynamoDBMapper`를 사용하여 테이블을 스캔할 수 있습니다. 예를 들어, 다음 Java 코드에서는 전체 `Reply` 테이블을 스캔하여 특정 연도의 회신만 반환합니다.

**Example**  

```
HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1", new AttributeValue().withS("2015"));

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withFilterExpression("begins_with(ReplyDateTime,:v1)")
    .withExpressionAttributeValues(eav);

List<Reply> replies =  mapper.scan(Reply.class, scanExpression);
```

기본적으로 `scan` 메서드는 "지연 로딩된(lazy-loaded)" 컬렉션을 반환합니다. 즉, 처음에는 결과 페이지를 하나만 반환하고, 필요에 따라 서비스를 호출하여 다음 페이지를 반환합니다. 일치하는 항목을 모두 가져오려면 `replies` 컬렉션을 반복합니다.

컬렉션에서 `size()` 메서드를 호출하면 정확한 개수를 제공하기 위해 모든 결과가 로드됩니다. 이로 인해 프로비저닝된 처리량이 많이 사용될 수 있으며, 매우 큰 테이블에서는 JVM의 모든 메모리가 소모될 수도 있습니다.

인덱스를 스캔하려면 먼저 인덱스를 매퍼 클래스로 모델링해야 합니다. `Reply` 테이블에 `PostedBy-Message-Index`라는 글로벌 보조 인덱스가 있다고 가정합니다. 이 인덱스의 파티션 키는 `PostedBy`이고, 정렬 키는 `Message`입니다. 이 인덱스에 대한 매퍼 클래스는 [쿼리](#DynamoDBMapper.Methods.query) 단원에 나와 있습니다. 이 클래스는 `@DynamoDBIndexHashKey` 및 `@DynamoDBIndexRangeKey` 주석을 사용하여 인덱스 파티션 키 및 정렬 키를 지정합니다.

다음 코드 예제에서는 `PostedBy-Message-Index`를 스캔합니다. 스캔 필터를 사용하지 않으므로 인덱스의 모든 항목이 반환됩니다.

```
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withIndexName("PostedBy-Message-Index")
    .withConsistentRead(false);

    List<PostedByMessage> iList =  mapper.scan(PostedByMessage.class, scanExpression);
    Iterator<PostedByMessage> indexItems = iList.iterator();
```

## scanPage
<a name="DynamoDBMapper.Methods.scanPage"></a>

테이블 또는 보조 인덱스를 스캔하고 일치하는 결과를 단일 페이지로 반환합니다. `scan` 메서드와 마찬가지로 `FilterExpression`을 지정하여 결과 집합을 필터링할 수도 있습니다(선택 사항). 그러나 `scanPage`는 첫 번째 데이터 ‘페이지’만 반환합니다. 다시 말해서 1MB를 넘지 않는 범위에서 데이터를 반환합니다.

## parallelScan
<a name="DynamoDBMapper.Methods.parallelScan"></a>

전체 테이블 또는 보조 인덱스를 병렬 방식으로 스캔합니다. 즉, 결과를 필터링할 스캔 표현식과 함께 테이블의 논리 세그먼트를 다수 지정합니다. `parallelScan`은 스캔 작업을 각 논리 세그먼트마다 하나씩 여러 작업자로 분할합니다. 그러면 작업자가 데이터를 병렬 방식으로 처리하여 결과를 반환합니다.

다음 Java 코드 예제에서는 `Product` 테이블에 대한 병렬 스캔을 수행합니다.

```
int numberOfThreads = 4;

Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":n", new AttributeValue().withN("100"));

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withFilterExpression("Price <= :n")
    .withExpressionAttributeValues(eav);

List<Product> scanResult = mapper.parallelScan(Product.class, scanExpression, numberOfThreads);
```

## batchSave
<a name="DynamoDBMapper.Methods.batchSave"></a>

`AmazonDynamoDB.batchWriteItem` 메서드를 1회 이상 호출하여 객체를 하나 이상의 테이블에 저장합니다. 이 메서드는 트랜잭션을 보장하지는 않습니다.

다음 Java 코드에서는 두 항목(책)을 `ProductCatalog` 테이블에 저장합니다.

```
Book book1 = new Book();
book1.setId(901);
book1.setProductCategory("Book");
book1.setTitle("Book 901 Title");

Book book2 = new Book();
book2.setId(902);
book2.setProductCategory("Book");
book2.setTitle("Book 902 Title");

mapper.batchSave(Arrays.asList(book1, book2));
```

## batchLoad
<a name="DynamoDBMapper.Methods.batchLoad"></a>

기본 키를 사용하여 다수의 항목을 하나 이상의 테이블에서 가져옵니다.

다음 Java 코드에서는 두 개의 서로 다른 테이블에서 두 개의 항목을 검색합니다.

```
ArrayList<Object> itemsToGet = new ArrayList<Object>();

ForumItem forumItem = new ForumItem();
forumItem.setForumName("Amazon DynamoDB");
itemsToGet.add(forumItem);

ThreadItem threadItem = new ThreadItem();
threadItem.setForumName("Amazon DynamoDB");
threadItem.setSubject("Amazon DynamoDB thread 1 message text");
itemsToGet.add(threadItem);

Map<String, List<Object>> items = mapper.batchLoad(itemsToGet);
```

## batchDelete
<a name="DynamoDBMapper.Methods.batchDelete"></a>

`AmazonDynamoDB.batchWriteItem` 메서드를 1회 이상 호출하여 객체를 하나 이상의 테이블에서 삭제합니다. 이 메서드는 트랜잭션을 보장하지는 않습니다.

다음은 Java 코드에서는 `ProductCatalog` 테이블에서 두 항목(책)을 삭제합니다.

```
Book book1 = mapper.load(Book.class, 901);
Book book2 = mapper.load(Book.class, 902);
mapper.batchDelete(Arrays.asList(book1, book2));
```

## batchWrite
<a name="DynamoDBMapper.Methods.batchWrite"></a>

`AmazonDynamoDB.batchWriteItem` 메서드를 1회 이상 호출하여 객체를 하나 이상의 테이블에 저장하거나 삭제합니다. 이 메서드는 트랜잭션을 보장하거나 버전 관리를 지원하지 않습니다(조건부 업로드 또는 삭제).

다음 Java 코드에서는 새 항목을 `Forum` 테이블에 쓰고, 새 항목을 `Thread` 테이블에 쓰고, `ProductCatalog` 테이블에서 항목을 삭제합니다.

```
// Create a Forum item to save
Forum forumItem = new Forum();
forumItem.setName("Test BatchWrite Forum");

// Create a Thread item to save
Thread threadItem = new Thread();
threadItem.setForumName("AmazonDynamoDB");
threadItem.setSubject("My sample question");

// Load a ProductCatalog item to delete
Book book3 = mapper.load(Book.class, 903);

List<Object> objectsToWrite = Arrays.asList(forumItem, threadItem);
List<Book> objectsToDelete = Arrays.asList(book3);

mapper.batchWrite(objectsToWrite, objectsToDelete);
```

## transactionWrite
<a name="DynamoDBMapper.Methods.transactionWrite"></a>

`AmazonDynamoDB.transactWriteItems` 메서드를 1회 호출하여 객체를 하나 이상의 테이블에 저장하거나 삭제합니다.

트랜잭션별 예외 목록을 보려면 [TransactWriteItems 오류](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html#API_TransactWriteItems_Errors)를 참조하세요.

DynamoDB 트랜잭션과 제공된 원자성, 일관성, 격리성 및 지속성(ACID) 보장에 대한 자세한 내용은 [Amazon DynamoDB Transactions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)를 참조하세요.

**참고**  
 이 메서드는 다음을 지원하지 않습니다.  
[DynamoDBMapperConfig.SaveBehavior](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptionalConfig.html).

다음 Java 코드에서는 트랜잭션 형태로 각 `Forum` 및 `Thread` 테이블에 새 항목을 씁니다.

```
Thread s3ForumThread = new Thread();
s3ForumThread.setForumName("S3 Forum");
s3ForumThread.setSubject("Sample Subject 1");
s3ForumThread.setMessage("Sample Question 1");

Forum s3Forum = new Forum();
s3Forum.setName("S3 Forum");
s3Forum.setCategory("Amazon Web Services");
s3Forum.setThreads(1);

TransactionWriteRequest transactionWriteRequest = new TransactionWriteRequest();
transactionWriteRequest.addPut(s3Forum);
transactionWriteRequest.addPut(s3ForumThread);
mapper.transactionWrite(transactionWriteRequest);
```

## transactionLoad
<a name="DynamoDBMapper.Methods.transactionLoad"></a>

`AmazonDynamoDB.transactGetItems` 메서드를 1회 호출하여 객체를 하나 이상의 테이블에서 로드합니다.

트랜잭션별 예외 목록을 보려면 [TransactGetItems 오류](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html#API_TransactGetItems_Errors)를 참조하세요.

DynamoDB 트랜잭션과 제공된 원자성, 일관성, 격리성 및 지속성(ACID) 보장에 대한 자세한 내용은 [Amazon DynamoDB Transactions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)를 참조하세요.

다음 Java 코드에서는 트랜잭션 형태로 각 `Forum` 및 `Thread` 테이블에서 한 개의 항목을 로드합니다.

```
Forum dynamodbForum = new Forum();
dynamodbForum.setName("DynamoDB Forum");
Thread dynamodbForumThread = new Thread();
dynamodbForumThread.setForumName("DynamoDB Forum");

TransactionLoadRequest transactionLoadRequest = new TransactionLoadRequest();
transactionLoadRequest.addLoad(dynamodbForum);
transactionLoadRequest.addLoad(dynamodbForumThread);
mapper.transactionLoad(transactionLoadRequest);
```

## count
<a name="DynamoDBMapper.Methods.count"></a>

지정한 스캔 표현식을 평가하여 일치하는 항목 수를 반환합니다. 항목 데이터를 따로 반환하지는 않습니다.

## generateCreateTableRequest
<a name="DynamoDBMapper.Methods.generateCreateTableRequest"></a>

DynamoDB 테이블을 나타내는 POJO 클래스를 구문 분석한 다음 해당 테이블의 `CreateTableRequest`를 반환합니다.

## createS3Link
<a name="DynamoDBMapper.Methods.createS3Link"></a>

Amazon S3 객체에 대한 링크를 생성합니다. 이때 버킷 객체의 고유 식별자로서 버킷 이름과 키 이름을 지정해야 합니다.

`createS3Link`를 사용하려면 접근자(getter/setter) 메서드를 정의해야 합니다. 다음 코드 예제에서는 새 속성 및 getter/setter 메서드를 `CatalogItem` 클래스에 추가하여 이를 설명합니다.

```
@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {

    ...

    public S3Link productImage;

    ....

    @DynamoDBAttribute(attributeName = "ProductImage")
    public S3Link getProductImage() {
            return productImage;
    }

    public void setProductImage(S3Link productImage) {
        this.productImage = productImage;
    }

...
}
```

다음 Java 코드에서는 `Product` 테이블에 쓸 새 항목을 정의합니다. 코드를 보면 항목에 제품 이미지 링크가 추가되어 있습니다. 이 이미지 데이터는 Amazon S3에 업로드됩니다.

```
CatalogItem item = new CatalogItem();

item.setId(150);
item.setTitle("Book 150 Title");

String amzn-s3-demo-bucket = "amzn-s3-demo-bucket";
String myS3Key = "productImages/book_150_cover.jpg";
item.setProductImage(mapper.createS3Link(amzn-s3-demo-bucket, myS3Key));

item.getProductImage().uploadFrom(new File("/file/path/book_150_cover.jpg"));

mapper.save(item);
```

`S3Link` 클래스는 Amazon S3의 객체를 조작할 수 있는 여러 가지 다른 메서드를 제공합니다. 자세한 내용은 [`S3Link` Javadocs](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/S3Link.html)를 참조하세요.

## getS3ClientCache
<a name="DynamoDBMapper.Methods.getS3ClientCache"></a>

Amazon S3에 액세스할 수 있는 기본 `S3ClientCache`를 반환합니다. `S3ClientCache`는 `AmazonS3Client` 객체를 위한 스마트 맵입니다. 클라이언트가 다수일 때는 `S3ClientCache`가 AWS 리전별로 클라이언트를 구성하는 데 효과적일 뿐만 아니라 필요하다면 새 Amazon S3 클라이언트를 생성할 수도 있습니다.

# Java용 DynamoDBMapper에서 지원되는 데이터 형식
<a name="DynamoDBMapper.DataTypes"></a>

이 단원에서는 Amazon DynamoDB에서 지원되는 기본 Java 데이터 형식, 컬렉션 및 임의의 데이터 형식을 설명합니다.

Amazon DynamoDB는 다음과 같은 기본 Java 데이터 형식 및 기본 래퍼 클래스를 지원합니다.
+ `String`
+ `Boolean`, `boolean`
+ `Byte`, `byte`
+ `Date`([ISO\$18601](http://en.wikipedia.org/wiki/ISO_8601) 밀리초 정밀도 문자열에 따라 UTC로 전환)
+ `Calendar`([ISO\$18601](http://en.wikipedia.org/wiki/ISO_8601) 밀리초 정밀도 문자열에 따라 UTC로 전환)
+ `Long`, `long`
+ `Integer`, `int`
+ `Double`, `double`
+ `Float`, `float`
+ `BigDecimal`
+ `BigInteger`

**참고**  
DynamoDB 이름 지정 규칙 및 지원되는 다양한 데이터 형식에 대한 자세한 내용은 [Amazon DynamoDB에서 지원되는 데이터 형식 및 이름 지정 규칙](HowItWorks.NamingRulesDataTypes.md) 단원을 참조하세요.
DynamoDBMapper에서 빈 이진수 값이 지원됩니다.
AWS SDK for Java 2.x에서 빈 문자열 값이 지원됩니다.  
AWS SDK for Java 1.x에서 DynamoDBMapper는 빈 문자열 속성 값 읽기를 지원하지만, 해당 속성이 요청에서 삭제되므로 빈 문자열 속성 값을 쓰지 않습니다.

DynamoDB는 Java [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html), [List](http://docs.oracle.com/javase/6/docs/api/java/util/List.html) 및 [Map](http://docs.oracle.com/javase/6/docs/api/java/util/Map.html) 컬렉션 형식을 지원합니다. 다음 표에는 이러한 Java 형식이 DynamoDB 형식으로 매핑되는 방법이 요약되어 있습니다.


****  

| Java 형식 | DynamoDB 형식 | 
| --- | --- | 
|  모두 숫자 형식  |  `N`(숫자 형식)  | 
|  문자열  |  `S`(문자열 형식)   | 
|  부울  |  `BOOL`(부울 형식), 0 또는 1  | 
|  ByteBuffer  |  `B`(이진수 형식)  | 
|  날짜  |  `S`(문자열 형식) 날짜 값은 ISO-8601 포맷 문자열로 저장됩니다.  | 
| [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html)(집합) 컬렉션 형식 |  `SS`(문자열 집합) 형식, `NS`(숫자 집합) 형식, 또는 `BS`(이진수 집합) 형식  | 

 `DynamoDBTypeConverter` 인터페이스를 사용하면 자체적인 임의 데이터 형식을 DynamoDB에서 기본적으로 지원되는 데이터 형식으로 매핑할 수 있습니다. 자세한 내용은 [DynamoDB에서 임의 데이터 매핑](DynamoDBMapper.ArbitraryDataMapping.md) 섹션을 참조하세요.

# DynamoDB에 사용되는 Java 주석
<a name="DynamoDBMapper.Annotations"></a>

이 단원에서는 클래스 및 속성을 Amazon DynamoDB의 테이블 및 속성으로 매핑하는 데 사용되는 주석을 설명합니다.

해당 Javadoc 설명서는 [AWS SDK for Java API 참조](https://docs.aws.amazon.com/sdk-for-java/latest/reference/)의 [주석 유형 요약](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/package-summary.html) 단원을 참조하세요.

**참고**  
다음 주석에서 `DynamoDBTable` 및 `DynamoDBHashKey`만 필요합니다.

**Topics**
+ [DynamoDBAttribute](#DynamoDBMapper.Annotations.DynamoDBAttribute)
+ [DynamoDBAutoGeneratedKey](#DynamoDBMapper.Annotations.DynamoDBAutoGeneratedKey)
+ [DynamoDBAutoGeneratedTimestamp](#DynamoDBMapper.Annotations.DynamoDBAutoGeneratedTimestamp)
+ [DynamoDBDocument](#DynamoDBMapper.Annotations.DynamoDBDocument)
+ [DynamoDBHashKey](#DynamoDBMapper.Annotations.DynamoDBHashKey)
+ [DynamoDBIgnore](#DynamoDBMapper.Annotations.DynamoDBIgnore)
+ [DynamoDBIndexHashKey](#DynamoDBMapper.Annotations.DynamoDBIndexHashKey)
+ [DynamoDBIndexRangeKey](#DynamoDBMapper.Annotations.DynamoDBIndexRangeKey)
+ [DynamoDBRangeKey](#DynamoDBMapper.Annotations.DynamoDBRangeKey)
+ [DynamoDBTable](#DynamoDBMapper.Annotations.DynamoDBTable)
+ [DynamoDBTypeConverted](#DynamoDBMapper.Annotations.DynamoDBTypeConverted)
+ [DynamoDBTyped](#DynamoDBMapper.Annotations.DynamoDBTyped)
+ [DynamoDBVersionAttribute](#DynamoDBMapper.Annotations.DynamoDBVersionAttribute)

## DynamoDBAttribute
<a name="DynamoDBMapper.Annotations.DynamoDBAttribute"></a>

속성을 테이블 속성으로 매핑합니다. 기본적으로 각 클래스 속성은 이름이 동일한 항목 속성으로 매핑됩니다. 하지만 이름이 다를 경우에는 이 주석을 사용하여 클래스 속성을 테이블 속성으로 매핑할 수 있습니다. 아래 Java 코드 조각에서는 `DynamoDBAttribute`가 `BookAuthors` 속성을 테이블의 속성 이름으로 매핑하고 있습니다.`Authors`

```
@DynamoDBAttribute(attributeName = "Authors")
public List<String> getBookAuthors() { return BookAuthors; }
public void setBookAuthors(List<String> BookAuthors) { this.BookAuthors = BookAuthors; }
```

`DynamoDBMapper`가 객체를 테이블에 저장할 때는 `Authors`를 속성 이름으로 사용합니다.

## DynamoDBAutoGeneratedKey
<a name="DynamoDBMapper.Annotations.DynamoDBAutoGeneratedKey"></a>

파티션 키 또는 정렬 키 속성을 자동 생성되는 것으로 표시합니다. `DynamoDBMapper`는 이러한 속성을 저장할 때 임의의 [UUID](http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html)를 생성합니다. String 속성만 자동 생성된 키로 표시될 수 있습니다.

다음 예제에서는 자동 생성된 키를 사용하는 방법을 보여줍니다.

```
@DynamoDBTable(tableName="AutoGeneratedKeysExample")
public class AutoGeneratedKeys {
    private String id;
    private String payload;

    @DynamoDBHashKey(attributeName = "Id")
    @DynamoDBAutoGeneratedKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    @DynamoDBAttribute(attributeName="payload")
    public String getPayload() { return this.payload; }
    public void setPayload(String payload) { this.payload = payload; }

    public static void saveItem() {
        AutoGeneratedKeys obj = new AutoGeneratedKeys();
        obj.setPayload("abc123");

        // id field is null at this point
        DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
        mapper.save(obj);

        System.out.println("Object was saved with id " + obj.getId());
    }
}
```

## DynamoDBAutoGeneratedTimestamp
<a name="DynamoDBMapper.Annotations.DynamoDBAutoGeneratedTimestamp"></a>

자동으로 타임스탬프를 생성합니다.

```
@DynamoDBAutoGeneratedTimestamp(strategy=DynamoDBAutoGenerateStrategy.ALWAYS)
public Date getLastUpdatedDate() { return lastUpdatedDate; }
public void setLastUpdatedDate(Date lastUpdatedDate) { this.lastUpdatedDate = lastUpdatedDate; }
```

원하는 경우 전략 속성을 제공하여 자동 생성 전략을 정의할 수 있습니다. 기본값은 `ALWAYS`입니다.

## DynamoDBDocument
<a name="DynamoDBMapper.Annotations.DynamoDBDocument"></a>

클래스를 Amazon DynamoDB 문서로 직렬화할 수 있음을 나타냅니다.

예를 들어, JSON 문서를 Map 형식(`M`)의 DynamoDB 속성으로 매핑하려는 경우 다음 코드 예제에서는 Map 유형의 중첩된 속성(Pictures)을 포함하는 항목을 정의합니다.

```
public class ProductCatalogItem {

    private Integer id;  //partition key
    private Pictures pictures;
    /* ...other attributes omitted... */

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id;}
    public void setId(Integer id) {this.id = id;}

    @DynamoDBAttribute(attributeName="Pictures")
    public Pictures getPictures() { return pictures;}
    public void setPictures(Pictures pictures) {this.pictures = pictures;}

    // Additional properties go here.

    @DynamoDBDocument
    public static class Pictures {
        private String frontView;
        private String rearView;
        private String sideView;

        @DynamoDBAttribute(attributeName = "FrontView")
        public String getFrontView() { return frontView; }
        public void setFrontView(String frontView) { this.frontView = frontView; }

        @DynamoDBAttribute(attributeName = "RearView")
        public String getRearView() { return rearView; }
        public void setRearView(String rearView) { this.rearView = rearView; }

        @DynamoDBAttribute(attributeName = "SideView")
        public String getSideView() { return sideView; }
        public void setSideView(String sideView) { this.sideView = sideView; }

     }
}
```

그러면 다음 예제와 같이 새 `ProductCatalog` 항목을 `Pictures`와 함께 저장할 수 있습니다.

```
ProductCatalogItem item = new ProductCatalogItem();

Pictures pix = new Pictures();
pix.setFrontView("http://example.com/products/123_front.jpg");
pix.setRearView("http://example.com/products/123_rear.jpg");
pix.setSideView("http://example.com/products/123_left_side.jpg");
item.setPictures(pix);

item.setId(123);

mapper.save(item);
```

결과로 얻은 `ProductCatalog` 항목은 다음과 같을 것입니다(JSON 형식).

```
{
  "Id" : 123
  "Pictures" : {
    "SideView" : "http://example.com/products/123_left_side.jpg",
    "RearView" : "http://example.com/products/123_rear.jpg",
    "FrontView" : "http://example.com/products/123_front.jpg"
  }
}
```

## DynamoDBHashKey
<a name="DynamoDBMapper.Annotations.DynamoDBHashKey"></a>

클래스 속성을 테이블의 파티션 키 속성으로 매핑합니다. 속성은 스칼라 문자열, 숫자 또는 이진수 형식 중 하나여야 합니다. 속성은 컬렉션 형식일 수 없습니다.

`ProductCatalog` 테이블이 있고 이 테이블에서 기본 키로 `Id`를 사용하는 경우 다음 Java 코드에서는 `CatalogItem` 클래스를 정의하고 `Id` 태그를 사용하여 해당 `ProductCatalog` 속성을 `@DynamoDBHashKey` 테이블의 기본 키로 매핑합니다.

```
@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {
    private Integer Id;
   @DynamoDBHashKey(attributeName="Id")
   public Integer getId() {
        return Id;
   }
   public void setId(Integer Id) {
        this.Id = Id;
   }
   // Additional properties go here.
}
```

## DynamoDBIgnore
<a name="DynamoDBMapper.Annotations.DynamoDBIgnore"></a>

`DynamoDBMapper` 인스턴스에게 연동되어 있는 속성을 무시하라고 지시합니다. 그러면 데이터를 테이블에 저장할 때도 `DynamoDBMapper`는 이 속성을 테이블에 저장하지 않습니다.

 모델링되지 않은 속성의 클래스 필드 또는 getter 메서드에 적용됩니다. 클래스 필드에 주석이 직접 적용되는 경우 해당 getter 및 setter를 동일한 클래스에 선언해야 합니다.

## DynamoDBIndexHashKey
<a name="DynamoDBMapper.Annotations.DynamoDBIndexHashKey"></a>

클래스 속성을 글로벌 보조 인텍스의 파티션 키로 매핑합니다. 속성은 스칼라 문자열, 숫자 또는 이진수 형식 중 하나여야 합니다. 속성은 컬렉션 형식일 수 없습니다.

이 주석은 글로벌 보조 인덱스를 `Query`해야 하는 경우 사용합니다. 이때는 인덱스 이름(`globalSecondaryIndexName`)을 지정해야 합니다. 클래스 속성 이름이 인덱스 파티션 키와 다른 경우 인덱스 속성 이름(`attributeName`)도 지정해야 합니다.

## DynamoDBIndexRangeKey
<a name="DynamoDBMapper.Annotations.DynamoDBIndexRangeKey"></a>

클래스 속성을 글로벌 보조 인덱스 또는 로컬 보조 인덱스의 정렬 키로 매핑합니다. 속성은 스칼라 문자열, 숫자 또는 이진수 형식 중 하나여야 합니다. 속성은 컬렉션 형식일 수 없습니다.

이 주석은 로컬 보조 주석 또는 글로벌 보조 주석을 `Query`해야 하고 인덱스 정렬 키를 사용해 결과를 구체화하고 싶을 때 사용합니다. 이때는 인덱스 이름(`globalSecondaryIndexName` 또는 `localSecondaryIndexName`)을 지정해야 합니다. 그리고 클래스 속성 이름과 인덱스 정렬 키가 다른 경우에는 인덱스 속성 이름(`attributeName`)도 지정해야 합니다.

## DynamoDBRangeKey
<a name="DynamoDBMapper.Annotations.DynamoDBRangeKey"></a>

클래스 속성을 테이블의 정렬 키 속성으로 매핑합니다. 속성은 스칼라 문자열, 숫자 또는 이진수 형식 중 하나여야 합니다. 속성은 컬렉션 형식일 수 없습니다.

기본 키가 복합형(파티션 키 및 정렬 키)일 경우 이 태그를 사용하여 클래스 필드를 정렬 키로 매핑할 수 있습니다. 예를 들어, 포럼 스레드에 대한 회신을 저장하는 `Reply` 테이블이 있는 경우 스레드마다 다수의 댓글을 가질 수 있습니다. 따라서 이 테이블의 기본 키는 `ThreadId` 및 `ReplyDateTime`입니다. `ThreadId`는 파티션 키이고, `ReplyDateTime`은 정렬 키입니다.

다음은 `Reply` 클래스를 정의하여 `Reply` 테이블에 매핑하는 Java 코드입니다. 코드 조각을 보면 `@DynamoDBHashKey` 및 `@DynamoDBRangeKey` 태그를 사용하여 기본 키에 매핑되는 클래스 속성을 식별하고 있습니다.

```
@DynamoDBTable(tableName="Reply")
public class Reply {
    private Integer id;
    private String replyDateTime;

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }

    @DynamoDBRangeKey(attributeName="ReplyDateTime")
    public String getReplyDateTime() { return replyDateTime; }
    public void setReplyDateTime(String replyDateTime) { this.replyDateTime = replyDateTime; }

   // Additional properties go here.
}
```

## DynamoDBTable
<a name="DynamoDBMapper.Annotations.DynamoDBTable"></a>

DynamoDB의 대상 테이블을 식별합니다. 예를 들어, 다음 Java 코드는 `Developer` 클래스를 정의하여 DynamoDB의 `People` 테이블에 매핑합니다.

```
@DynamoDBTable(tableName="People")
public class Developer { ...}
```

`@DynamoDBTable` 주석은 상속이 가능합니다. `Developer` 클래스에서 상속되는 새 클래스도 `People` 테이블로 매핑됩니다. 예를 들어 `Lead` 클래스를 `Developer` 클래스에서 상속하여 생성한다고 가정하겠습니다. `Developer` 클래스를 `People` 테이블로 매핑했기 때문에 `Lead` 클래스 객체도 동일한 테이블에 저장됩니다.

`@DynamoDBTable` 또한 재정의가 가능합니다. 기본적으로 `Developer` 클래스에서 상속되는 새 클래스는 모두 동일한 `People` 테이블로 매핑됩니다. 하지만 이 기본 매핑을 재정의할 수도 있습니다. 예를 들어, `Developer` 클래스에서 상속되는 클래스를 생성하는 경우 다음 Java 코드 예제와 같이 `@DynamoDBTable` 주석을 추가하여 해당 클래스를 다른 테이블로 명시적으로 매핑할 수 있습니다.

```
@DynamoDBTable(tableName="Managers")
public class Manager extends Developer { ...}
```

## DynamoDBTypeConverted
<a name="DynamoDBMapper.Annotations.DynamoDBTypeConverted"></a>

속성을 사용자 지정 유형 변환기를 사용하는 것으로 표시하는 주석 `DynamoDBTypeConverter`에 추가 속성을 전달하기 위한 사용자 정의 주석에 작성할 수 있습니다.

 `DynamoDBTypeConverter` 인터페이스를 사용하면 자체적인 임의 데이터 형식을 DynamoDB에서 기본적으로 지원되는 데이터 형식으로 매핑할 수 있습니다. 자세한 내용은 [DynamoDB에서 임의 데이터 매핑](DynamoDBMapper.ArbitraryDataMapping.md) 섹션을 참조하세요.

## DynamoDBTyped
<a name="DynamoDBMapper.Annotations.DynamoDBTyped"></a>

표준 속성 형식 바인딩을 재정의하는 주석 표준 형식에서 해당 형식에 기본 속성 바인딩을 적용할 경우 주석이 필요하지 않습니다.

## DynamoDBVersionAttribute
<a name="DynamoDBMapper.Annotations.DynamoDBVersionAttribute"></a>

낙관적 잠금 버전 번호를 저장하는 클래스 속성을 식별합니다. `DynamoDBMapper`는 새로운 항목을 저장할 때 버전 번호를 이 속성에 할당한 후 항목을 업데이트할 때마다 버전 번호를 올립니다. 여기서는 숫자 스칼라 형식만 지원됩니다. 데이터 형식에 대한 자세한 내용은 [데이터 타입](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes) 단원을 참조하세요. 버전 관리에 대한 자세한 내용은 [DynamoDB 및 버전 번호를 이용한 낙관적 잠금](DynamoDBMapper.OptimisticLocking.md) 섹션을 참조하십시오.

# DynamoDBMapper의 구성 설정(선택 사항)
<a name="DynamoDBMapper.OptionalConfig"></a>

`DynamoDBMapper`의 인스턴스를 생성할 때는 일정한 기본 동작이 있지만 `DynamoDBMapperConfig` 클래스를 사용하면 이러한 기본 동작을 재정의할 수 있습니다.

다음은 사용자 지정 설정으로 `DynamoDBMapper`를 생성하는 코드 조각입니다.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();

DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder()
        .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER)
        .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT)
        .withTableNameOverride(null)
        .withPaginationLoadingStrategy(DynamoDBMapperConfig.PaginationLoadingStrategy.EAGER_LOADING)
    .build();

DynamoDBMapper mapper = new DynamoDBMapper(client, mapperConfig);
```

자세한 내용은 [AWS SDK for Java API 참조](https://docs.aws.amazon.com/sdk-for-java/latest/reference/)에서 [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.html)를 참조하세요.

`DynamoDBMapperConfig` 인스턴스에 사용할 수 있는 인수는 다음과 같습니다.
+ `DynamoDBMapperConfig.ConsistentReads` 열거 값:
  + `EVENTUAL` - 매퍼 인스턴스가 최종적으로 일관된 읽기 요청을 사용합니다.
  + `CONSISTENT` - 매퍼 인스턴스가 강력히 일관된 읽기 요청을 사용합니다. 이 옵션 설정은 `load`, `query` 또는 `scan` 작업에 사용할 수 있습니다. 강력히 일관된 읽기는 성능과 결제에 영향을 미칩니다. 자세한 내용은 DynamoDB [제품 세부 정보 페이지](https://aws.amazon.com/dynamodb)를 참조하세요.

  매퍼 인스턴스에 읽기 일관성 설정을 지정하지 않으면 `EVENTUAL`이 기본값으로 설정됩니다.
**참고**  
이 값은 DynamoDBMapper의 `query`, `querypage`, `load` 및 `batch load` 작업에만 적용됩니다.
+ `DynamoDBMapperConfig.PaginationLoadingStrategy` 열거 값 - 매퍼 인스턴스가 `query` 또는`scan`의 결과와 같은 페이지 매긴 데이터 목록을 처리하는 방식을 제어합니다.
  + `LAZY_LOADING` - 매퍼 인스턴스는 가능할 경우 데이터를 로드하고, 로드한 결과를 모두 메모리에 저장합니다.
  + `EAGER_LOADING` - 목록 초기화 직후 매퍼 인스턴스가 데이터를 로드합니다.
  + `ITERATION_ONLY` - 반복자를 사용해야만 목록에서 읽을 수 있습니다. 반복 단계에서는 다음 페이지를 로드하기 전에 이전 결과가 목록에서 사라집니다. 따라서 로드된 결과는 단일 페이지 목록으로만 메모리에 저장합니다. 이는 목록의 반복 횟수가 1회로 제한된다는 것을 의미하기도 합니다. 이러한 전략은 다수의 항목을 처리하면서 메모리 오버헤드를 줄여야 할 때 바람직합니다.

  매퍼 인스턴스에 페이지 매김 로딩 전략을 지정하지 않으면 `LAZY_LOADING`이 기본값으로 설정됩니다.
+ `DynamoDBMapperConfig.SaveBehavior` 열거 값 - 저장 작업 시 매퍼 인스턴스의 속성 처리 방식을 지정합니다.
  + `UPDATE` - 저장 작업 중 모델링된 속성만 모두 업데이트되고 모델링되지 않은 속성은 업데이트되지 않습니다. 기본적인 숫자 형식(byte, int, long)은 0으로 설정됩니다. 그리고 객체 형식은 null로 설정됩니다.
  + `CLOBBER` - 저장 작업 중 모델링되지 않은 속성을 비롯하여 모든 속성을 지우고 교체합니다. 즉, 항목을 삭제했다가 다시 생성합니다. 버전이 지정된 필드 제약 조건 역시 무시됩니다.

   매퍼 인스턴스에 저장 동작을 지정하지 않으면 `UPDATE`가 기본값으로 설정됩니다.
**참고**  
DynamoDBMapper 트랜잭션 작업은 `DynamoDBMapperConfig.SaveBehavior` 열거를 지원하지 않습니다.
+ `DynamoDBMapperConfig.TableNameOverride` - 객체 매퍼 인스턴스에 클래스의 `DynamoDBTable` 주석으로 지정한 테이블 이름은 무시하고 대신에 직접 입력하는 다른 테이블 이름을 사용하도록 지시합니다. 이는 런타임에서 데이터를 여러 테이블로 분할할 때 유용합니다.

필요하다면 작업 단위로 `DynamoDBMapper`의 기본 구성 객체를 재정의할 수도 있습니다.

# DynamoDB 및 버전 번호를 이용한 낙관적 잠금
<a name="DynamoDBMapper.OptimisticLocking"></a>

*낙관적 잠금*은 업데이트 또는 삭제하려는 클라이언트 측 항목이 Amazon DynamoDB의 항목과 동일하도록 하려는 전략입니다. 이 전략을 사용하면 다른 사용자의 쓰기 작업이 자신의 데이터베이스 쓰기 작업을 덮어쓰지 못하도록 보호하며, 그 반대도 마찬가지입니다.

낙관적 잠금 전략에서는 각 항목마다 버전 번호 역할을 하는 속성이 있습니다. 항목을 테이블에서 가져오면 애플리케이션이 해당 항목의 버전 번호를 기록합니다. 이 항목을 업데이트할 수는 있지만 서버 쪽 버전 번호가 바뀌지 않는 경우에 한합니다. 버전 불일치가 있는 경우 사용자가 항목을 수정하기 전에 다른 사람이 해당 항목을 수정했음을 의미합니다. 더 이상 유효하지 않은 항목 버전이 있으므로 업데이트 시도가 실패합니다. 이러한 경우 항목을 검색한 후 해당 항목 업데이트를 시도하여 재시도합니다. 낙관적 잠금을 통해 다른 사람이 수행한 변경 사항을 잘못 덮어쓰지 않게 됩니다. 또한 다른 사람이 사용자의 변경 사항을 잘못 덮어쓰지 않도록 합니다.

자체적인 낙관적 잠금 전략을 구현할 수 있지만 AWS SDK for Java에서는 `@DynamoDBVersionAttribute` 주석을 제공합니다. 테이블 매핑 클래스에서 버전 번호를 저장할 속성을 하나 지정하여 이 주석을 사용해 표시하면 됩니다. 그러면 객체를 저장할 때 DynamoDB 테이블의 해당 항목이 버전 번호를 저장하는 속성을 갖게 됩니다. 처음 객체를 저장할 때 `DynamoDBMapper`가 버전 번호를 할당하고, 이후 항목을 업데이트할 때마다 버전 번호가 일정하게 자동으로 오릅니다. 업데이트 또는 삭제 요청은 클라이언트 측 객체 버전이 DynamoDB 테이블의 해당 항목 버전 번호와 일치해야만 가능합니다.

 `ConditionalCheckFailedException`다음의 경우 이 발생합니다.
+  `@DynamoDBVersionAttribute`를 이용한 낙관적 잠금을 사용하며, 서버의 버전 값이 클라이언트 측의 값과 다를 경우 
+  `DynamoDBMapper`과 함께 `DynamoDBSaveExpression`를 사용하여 데이터를 저장하는 동안 고유의 조건부 제약 조건을 지정하며 이러한 제약 조건이 실패한 경우 

**참고**  
DynamoDB 전역 테이블은 동시 업데이트 간에 "last writer wins" 조정을 사용합니다. 전역 테이블을 사용할 경우 last writer 정책을 우선 적용합니다. 따라서 잠금 전략이 작동하지 않습니다.
`DynamoDBMapper` 트랜잭션 쓰기 작업은 동일한 객체에 대해 `@DynamoDBVersionAttribute` 주석 및 조건 표현식을 지원하지 않습니다. 트랜잭션 쓰기 내 객체에 `@DynamoDBVersionAttribute` 주석이 추가되고 조건식도 있는 경우에는 SdkClientException이 발생합니다.

예를 들어, 다음 Java 코드에서는 몇 가지 속성이 있는 `CatalogItem` 클래스를 정의합니다. `Version` 속성이 `@DynamoDBVersionAttribute` 주석으로 표시되어 있습니다.

**Example**  

```
@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {

    private Integer id;
    private String title;
    private String ISBN;
    private Set<String> bookAuthors;
    private String someProp;
    private Long version;

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id; }
    public void setId(Integer Id) { this.id = Id; }

    @DynamoDBAttribute(attributeName="Title")
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }

    @DynamoDBAttribute(attributeName="ISBN")
    public String getISBN() { return ISBN; }
    public void setISBN(String ISBN) { this.ISBN = ISBN;}

    @DynamoDBAttribute(attributeName = "Authors")
    public Set<String> getBookAuthors() { return bookAuthors; }
    public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; }

    @DynamoDBIgnore
    public String getSomeProp() { return someProp;}
    public void setSomeProp(String someProp) {this.someProp = someProp;}

    @DynamoDBVersionAttribute
    public Long getVersion() { return version; }
    public void setVersion(Long version) { this.version = version;}
}
```

`@DynamoDBVersionAttribute` 주석을 `Long`이나 `Integer` 같이 null이 허용된 형식을 제공하는 기본 래퍼 클래스에서 제공하는 null 형식에 적용할 수 있습니다.

낙관적 잠금 전략은 이러한 `DynamoDBMapper` 메서드에 아래와 같은 영향을 끼칩니다.
+ `save` - 새 항목의 경우 `DynamoDBMapper`는 초기 버전 번호로 1을 할당합니다. 항목을 검색하고, 해당 속성 중 하나 이상을 업데이트하고, 변경 사항 저장을 시도하면 클라이언트 측 버전 번호와 서버 측 버전 번호가 일치하는 경우에만 저장 작업이 성공합니다. 그런 다음 `DynamoDBMapper`가 버전 번호를 자동으로 일정하게 올립니다.
+ `delete` - `delete` 메서드가 객체를 파라미터로 사용하고 `DynamoDBMapper`가 항목을 삭제하기 전에 버전을 검사합니다. 요청 시 `DynamoDBMapperConfig.SaveBehavior.CLOBBER`를 지정하면 버전 검사는 비활성화됩니다.

  `DynamoDBMapper`에서 낙관적 잠금을 내부 구현할 경우에는 DynamoDB가 제공하는 조건부 업데이트와 조건부 삭제 지원을 사용합니다.
+ `transactionWrite` —
  + `Put` - 새 항목의 경우 `DynamoDBMapper`는 초기 버전 번호로 1을 할당합니다. 이후 항목을 가져와 속성을 하나 이상 업데이트한 후 변경 사항을 저장하려고 해도 클라이언트 측과 서버 쪽의 버전 번호가 일치해야만 넣기 작업이 가능합니다. 그런 다음 `DynamoDBMapper`가 버전 번호를 자동으로 일정하게 올립니다.
  + `Update` - 새 항목의 경우 `DynamoDBMapper`는 초기 버전 번호로 1을 할당합니다. 이후 항목을 가져와 속성을 하나 이상 업데이트한 후 변경 사항을 저장하려고 해도 클라이언트 측과 서버 쪽의 버전 번호가 일치해야만 업데이트 작업이 가능합니다. 그런 다음 `DynamoDBMapper`가 버전 번호를 자동으로 일정하게 올립니다.
  + `Delete` - `DynamoDBMapper`는 항목을 삭제하기 전에 버전을 확인합니다. 클라이언트 측과 서버 측 버전 번호가 일치할 경우에만 삭제 작업이 가능합니다.
  + `ConditionCheck` - `@DynamoDBVersionAttribute` 주석은 `ConditionCheck` 작업에 지원되지 않습니다. `ConditionCheck` 항목에 `@DynamoDBVersionAttribute` 주석이 추가될 때 SdkClientException이 발생합니다.

## 낙관적 잠금 비활성화
<a name="DynamoDBMapper.OptimisticLocking.Disabling"></a>

낙관적 잠금은 `DynamoDBMapperConfig.SaveBehavior` 열거 값을 `UPDATE`에서 `CLOBBER`로 변경하면 비활성화할 수 있습니다. 그런 다음 버전 검사를 제외한 `DynamoDBMapperConfig` 인스턴스를 생성하여 모든 요청에 사용하면 됩니다. `DynamoDBMapperConfig.SaveBehavior`와 그 밖에 옵션으로 제공되는 `DynamoDBMapper` 파라미터에 대한 자세한 내용은 [DynamoDBMapper의 구성 설정(선택 사항)](DynamoDBMapper.OptionalConfig.md) 단원을 참조하세요.

또한 잠금 기능을 특정 작업에만 설정할 수도 있습니다. 예를 들어 다음은 `DynamoDBMapper`를 사용하여 카탈로그 항목을 저장하는 Java 코드 조각입니다. 이 조각을 보면 옵션인 `DynamoDBMapperConfig.SaveBehavior` 파라미터를 `DynamoDBMapperConfig` 메서드에 추가하여 `save`를 지정하고 있습니다.

**참고**  
transactionWrite 메서드는 DynamoDBMapperConfig.SaveBehavior 구성을 지원하지 않습니다. transactionWrite의 낙관적 잠금 비활성화는 지원되지 않습니다.

**Example**  

```
DynamoDBMapper mapper = new DynamoDBMapper(client);

// Load a catalog item.
CatalogItem item = mapper.load(CatalogItem.class, 101);
item.setTitle("This is a new title for the item");
...
// Save the item.
mapper.save(item,
    new DynamoDBMapperConfig(
        DynamoDBMapperConfig.SaveBehavior.CLOBBER));
```

# DynamoDB에서 임의 데이터 매핑
<a name="DynamoDBMapper.ArbitraryDataMapping"></a>

지원되는 Java 형식([Java용 DynamoDBMapper에서 지원되는 데이터 형식](DynamoDBMapper.DataTypes.md) 참조) 외에도 애플리케이션에서 직접적으로 Amazon DynamoDB 형식에 매핑되지 않는 형식을 사용할 수 있습니다. 이러한 형식을 매핑하려면 복합 형식을 DynamoDB 지원 형식으로 또는 그 반대로의 변환을 구현하고 `@DynamoDBTypeConverted` 주석을 사용하여 복합 형식의 접근자 메서드에 주석을 추가해야 합니다. 이후 객체를 저장하거나 로드하면 변환기 코드가 데이터를 변환합니다. 그 밖에 복합 형식을 사용하는 모든 작업에서도 유용합니다. 단, 쿼리나 스캔 작업 중 데이터를 비교하면 DynamoDB에 저장된 데이터를 비교하게 됩니다.

아래에서 `CatalogItem` 속성, 즉 `Dimension`을 정의하고 있는 `DimensionType` 클래스를 예로 들어보겠습니다. 이 속성에는 높이, 너비, 두께 등의 항목 차원이 저장됩니다. DynamoDB에서 이 항목 크기를 문자열(8.5x11x.05)로 저장한다고 가정할 때, 다음 예제를 보면 `DimensionType` 객체를 문자열로, 혹은 문자열을 `DimensionType`으로 변환하는 변환기 코드가 나와있습니다.



**참고**  
아래 코드 예제는 [DynamoDB에서 테이블 생성 및 코드 예시에 대한 데이터 로드](SampleData.md) 단원의 지침에 따라 이미 계정의 DynamoDB에 데이터를 로드하였다고 가정한 것입니다.  
다음 예제를 실행하기 위한 단계별 지침은 [Java 코드 예](CodeSamples.Java.md) 섹션을 참조하세요.

**Example**  

```
public class DynamoDBMapperExample {

    static AmazonDynamoDB client;

    public static void main(String[] args) throws IOException {

        // Set the AWS region you want to access.
        Regions usWest2 = Regions.US_WEST_2;
        client = AmazonDynamoDBClientBuilder.standard().withRegion(usWest2).build();

        DimensionType dimType = new DimensionType();
        dimType.setHeight("8.00");
        dimType.setLength("11.0");
        dimType.setThickness("1.0");

        Book book = new Book();
        book.setId(502);
        book.setTitle("Book 502");
        book.setISBN("555-5555555555");
        book.setBookAuthors(new HashSet<String>(Arrays.asList("Author1", "Author2")));
        book.setDimensions(dimType);

        DynamoDBMapper mapper = new DynamoDBMapper(client);
        mapper.save(book);

        Book bookRetrieved = mapper.load(Book.class, 502);
        System.out.println("Book info: " + "\n" + bookRetrieved);

        bookRetrieved.getDimensions().setHeight("9.0");
        bookRetrieved.getDimensions().setLength("12.0");
        bookRetrieved.getDimensions().setThickness("2.0");

        mapper.save(bookRetrieved);

        bookRetrieved = mapper.load(Book.class, 502);
        System.out.println("Updated book info: " + "\n" + bookRetrieved);
    }

    @DynamoDBTable(tableName = "ProductCatalog")
    public static class Book {
        private int id;
        private String title;
        private String ISBN;
        private Set<String> bookAuthors;
        private DimensionType dimensionType;

        // Partition key
        @DynamoDBHashKey(attributeName = "Id")
        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        @DynamoDBAttribute(attributeName = "Title")
        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        @DynamoDBAttribute(attributeName = "ISBN")
        public String getISBN() {
            return ISBN;
        }

        public void setISBN(String ISBN) {
            this.ISBN = ISBN;
        }

        @DynamoDBAttribute(attributeName = "Authors")
        public Set<String> getBookAuthors() {
            return bookAuthors;
        }

        public void setBookAuthors(Set<String> bookAuthors) {
            this.bookAuthors = bookAuthors;
        }

        @DynamoDBTypeConverted(converter = DimensionTypeConverter.class)
        @DynamoDBAttribute(attributeName = "Dimensions")
        public DimensionType getDimensions() {
            return dimensionType;
        }

        @DynamoDBAttribute(attributeName = "Dimensions")
        public void setDimensions(DimensionType dimensionType) {
            this.dimensionType = dimensionType;
        }

        @Override
        public String toString() {
            return "Book [ISBN=" + ISBN + ", bookAuthors=" + bookAuthors + ", dimensionType= "
                    + dimensionType.getHeight() + " X " + dimensionType.getLength() + " X "
                    + dimensionType.getThickness()
                    + ", Id=" + id + ", Title=" + title + "]";
        }
    }

    static public class DimensionType {

        private String length;
        private String height;
        private String thickness;

        public String getLength() {
            return length;
        }

        public void setLength(String length) {
            this.length = length;
        }

        public String getHeight() {
            return height;
        }

        public void setHeight(String height) {
            this.height = height;
        }

        public String getThickness() {
            return thickness;
        }

        public void setThickness(String thickness) {
            this.thickness = thickness;
        }
    }

    // Converts the complex type DimensionType to a string and vice-versa.
    static public class DimensionTypeConverter implements DynamoDBTypeConverter<String, DimensionType> {

        @Override
        public String convert(DimensionType object) {
            DimensionType itemDimensions = (DimensionType) object;
            String dimension = null;
            try {
                if (itemDimensions != null) {
                    dimension = String.format("%s x %s x %s", itemDimensions.getLength(), itemDimensions.getHeight(),
                            itemDimensions.getThickness());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return dimension;
        }

        @Override
        public DimensionType unconvert(String s) {

            DimensionType itemDimension = new DimensionType();
            try {
                if (s != null && s.length() != 0) {
                    String[] data = s.split("x");
                    itemDimension.setLength(data[0].trim());
                    itemDimension.setHeight(data[1].trim());
                    itemDimension.setThickness(data[2].trim());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return itemDimension;
        }
    }
}
```

# DynamoDBMapper 예제
<a name="DynamoDBMapper.Examples"></a>

AWS SDK for Java에서는 클라이언트 측 클래스를 DynamoDB 테이블로 매핑할 수 있는 `DynamoDBMapper` 클래스를 제공합니다. `DynamoDBMapper`를 사용하려면 코드에서 DynamoDB 테이블의 항목과 해당하는 객체 인스턴스 간의 관계를 정의합니다. `DynamoDBMapper` 클래스를 사용하면 항목에 대한 다양한 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행하고 테이블에 대한 쿼리 및 스캔을 실행할 수 있습니다.

`DynamoDBMapper` 사용 방법에 대한 자세한 내용은 *AWS SDK for Java 1.x 개발자 안내서*에 나와 있는 [AWS SDK for Java 사용에 관한 DynamoDB 예제](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-dynamodb.html)를 참조하시기 바랍니다.