

# DynamoDB에 대한 AWS SDK 지원 개요
<a name="Programming.SDKOverview"></a>

다음 다이어그램은 AWS SDK를 사용한 Amazon DynamoDB 애플리케이션 프로그래밍의 종합적 개요를 제공합니다.

![\[DynamoDB를 AWS SDK와 함께 사용하기 위한 프로그래밍 모델입니다.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/SDKSupport.png)


1. 해당 프로그래밍 언어의 AWS SDK를 사용하여 애플리케이션을 작성합니다.

1. 각각의 AWS SDK는 DynamoDB 작업을 위한 하나 이상의 프로그래밍 인터페이스를 제공합니다. 사용 가능한 특정 인터페이스는 사용하는 프로그래밍 언어와 AWS SDK에 따라 달라집니다. 옵션에는 다음이 포함됩니다.
   + [DynamoDB에서 작동하는 하위 수준 인터페이스](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.LowLevel)
   + [DynamoDB에서 작동하는 문서 인터페이스](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.Document)
   + [DynamoDB에서 작동하는 객체 지속성 인터페이스](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.Mapper)
   + [상위 수준 인터페이스](HigherLevelInterfaces.md)

1. AWS SDK가 하위 수준 DynamoDB API와 함께 사용할 HTTP(S) 요청을 구성합니다.

1. AWS SDK가 DynamoDB 엔드포인트에 요청을 보냅니다.

1. DynamoDB가 요청을 실행합니다. 요청이 성공하면 DynamoDB는 HTTP 200 응답 코드(OK)를 반환합니다. 요청이 실패하면 DynamoDB는 HTTP 오류 코드와 오류 메시지를 반환합니다.

1. AWS SDK는 응답을 처리하여 이를 다시 애플리케이션에 전파합니다.

각각의 AWS SDK가 애플리케이션에 제공하는 중요 서비스에는 다음이 포함됩니다.
+ HTTP(S) 요청 서식 설정 및 요청 파라미터 직렬화.
+ 각 요청의 암호화 서명 생성.
+ 요청을 DynamoDB 엔드포인트에 전달하고 DynamoDB에서 응답을 수신.
+ 이러한 응답에서 결과 추출.
+ 오류 발생 시 기본적 재시도 로직 구현.

이들 작업을 위한 코드는 작성할 필요가 없습니다.

**참고**  
설치 지침과 설명서 등 AWS SDK에 대한 자세한 내용은 [Amazon Web Services용 도구](https://aws.amazon.com/tools)를 참조하세요.

## SDK에서 AWS 계정 기반 엔드포인트 지원
<a name="Programming.SDKs.endpoints"></a>

AWS에서는 2024년 9월 4일 AWS SDK for Java V1을 시작으로 DynamoDB용 AWS 계정 기반 엔드포인트에 대한 SDK 지원을 롤아웃합니다. 이러한 새 엔드포인트는 AWS에서 높은 성능과 확장성을 보장하는 데 도움이 됩니다. 업데이트된 SDK는 `https://(account-id).ddb.(region).amazonaws.com` 형식을 가진 새 엔드포인트를 자동으로 사용합니다.

SDK 클라이언트의 단일 인스턴스를 사용하여 여러 계정에 요청을 보내는 경우 애플리케이션에서 연결을 재사용할 기회가 줄어듭니다. AWS에서는 SDK 클라이언트 인스턴스당 더 적은 수의 계정에 연결하도록 애플리케이션을 수정할 것을 권장합니다. 대안은 [https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html)에 설명된 대로 `ACCOUNT_ID_ENDPOINT_MODE` 설정을 사용하여 SDK 클라이언트가 리전 엔드포인트를 계속 사용하도록 설정하는 것입니다.

# DynamoDB에서 작동하는 프로그래밍 인터페이스
<a name="Programming.SDKs.Interfaces"></a>

각각의 [AWS SDK](https://aws.amazon.com/tools)는 Amazon DynamoDB 작업을 위한 하나 이상의 프로그래밍 인터페이스를 제공합니다. 이들 인터페이스는 단순한 하위 수준 DynamoDB 래퍼부터 객체 지향적인 지속성 계층까지 다양합니다. 사용 가능한 인터페이스는 사용하는 AWS SDK와 프로그래밍 언어에 따라 달라집니다.

![\[DynamoDB와 함께 사용할 수 있도록 다양한 AWS SDK에서 지원되는 프로그래밍 인터페이스입니다.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/SDKSupport.SDKInterfaces.png)


다음 단원에서는 AWS SDK for Java를 예제로 삼아 사용 가능한 몇 가지 인터페이스를 중점적으로 살펴봅니다. (AWS SDK에 따라 일부 인터페이스는 사용할 수 없습니다.)

**Topics**
+ [DynamoDB에서 작동하는 하위 수준 인터페이스](#Programming.SDKs.Interfaces.LowLevel)
+ [DynamoDB에서 작동하는 문서 인터페이스](#Programming.SDKs.Interfaces.Document)
+ [DynamoDB에서 작동하는 객체 지속성 인터페이스](#Programming.SDKs.Interfaces.Mapper)

## DynamoDB에서 작동하는 하위 수준 인터페이스
<a name="Programming.SDKs.Interfaces.LowLevel"></a>

모든 언어별 AWS SDK는 하위 수준 DynamoDB API 요청과 매우 비슷한 메서드를 사용하여 Amazon DynamoDB용 하위 수준 인터페이스를 제공합니다.

경우에 따라 [데이터 형식 서술자](Programming.LowLevelAPI.md#Programming.LowLevelAPI.DataTypeDescriptors)(예: 문자열의 경우 `N`, 숫자의 경우 `S`)을(를) 사용하여 속성의 데이터 형식을 식별해야 합니다.

**참고**  
하위 수준 인터페이스는 모든 언어별 AWS SDK에서 제공됩니다.

다음 Java 프로그램은 AWS SDK for Java의 하위 수준 인터페이스를 사용합니다.

### 하위 수준 인터페이스 예제
<a name="low-level-example"></a>

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 *
 * To get an item from an Amazon DynamoDB table using the AWS SDK for Java V2,
 * its better practice to use the
 * Enhanced Client, see the EnhancedGetItem example.
 */
public class GetItem {
    public static void main(String[] args) {
        final String usage = """

                Usage:
                    <tableName> <key> <keyVal>

                Where:
                    tableName - The Amazon DynamoDB table from which an item is retrieved (for example, Music3).\s
                    key - The key used in the Amazon DynamoDB table (for example, Artist).\s
                    keyval - The key value that represents the item to get (for example, Famous Band).
                """;

        if (args.length != 3) {
            System.out.println(usage);
            System.exit(1);
        }

        String tableName = args[0];
        String key = args[1];
        String keyVal = args[2];
        System.out.format("Retrieving item \"%s\" from \"%s\"\n", keyVal, tableName);
        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        getDynamoDBItem(ddb, tableName, key, keyVal);
        ddb.close();
    }

    public static void getDynamoDBItem(DynamoDbClient ddb, String tableName, String key, String keyVal) {
        HashMap<String, AttributeValue> keyToGet = new HashMap<>();
        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal)
                .build());

        GetItemRequest request = GetItemRequest.builder()
                .key(keyToGet)
                .tableName(tableName)
                .build();

        try {
            // If there is no matching item, GetItem does not return any data.
            Map<String, AttributeValue> returnedItem = ddb.getItem(request).item();
            if (returnedItem.isEmpty())
                System.out.format("No item found with the key %s!\n", key);
            else {
                Set<String> keys = returnedItem.keySet();
                System.out.println("Amazon DynamoDB table attributes: \n");
                for (String key1 : keys) {
                    System.out.format("%s: %s\n", key1, returnedItem.get(key1).toString());
                }
            }

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
}
```

## DynamoDB에서 작동하는 문서 인터페이스
<a name="Programming.SDKs.Interfaces.Document"></a>

많은 AWS SDK는 테이블과 인덱스에서 데이터 영역 작업(생성, 읽기, 업데이트, 삭제)을 수행할 수 있는 문서 인터페이스를 제공합니다. 문서 인터페이스를 사용하면 [데이터 형식 서술자](Programming.LowLevelAPI.md#Programming.LowLevelAPI.DataTypeDescriptors)를 지정할 필요가 없습니다. 데이터 형식은 데이터 자체의 의미론으로 암시됩니다. 이러한 AWS SDK는 JSON 문서를 기본 Amazon DynamoDB 데이터 형식으로, 또 그 반대로 쉽게 변환하는 메서드도 제공합니다.

**참고**  
문서 인터페이스는 AWS SDK for [Java](https://aws.amazon.com/sdk-for-java), [.NET](https://aws.amazon.com/sdk-for-net), [Node.js](https://aws.amazon.com/sdk-for-node-js), [JavaScript SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/)에서 사용할 수 있습니다.

다음 Java 프로그램은 AWS SDK for Java의 문서 인터페이스를 사용합니다. 이 프로그램은 `Table` 테이블을 나타내는 `Music` 객체를 생성한 다음 해당 객체에게 `GetItem`을 사용하여 노래를 검색하라고 요청합니다. 그런 다음 프로그램은 해당 노래가 발표된 연도를 인쇄합니다.

`software.amazon.dynamodb.document.DynamoDB` 클래스는 DynamoDB 문서 인터페이스를 구현합니다. `DynamoDB`가 어떻게 하위 수준 클라이언트(`AmazonDynamoDB`)를 둘러싼 래퍼 역할을 하는지에 유의하세요.

### 문서 인터페이스 예제
<a name="document-level-example"></a>

```
package com.amazonaws.codesamples.gsg;

import software.amazon.dynamodb.AmazonDynamoDB;
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import software.amazon.dynamodb.document.DynamoDB;
import software.amazon.dynamodb.document.GetItemOutcome;
import software.amazon.dynamodb.document.Table;

public class MusicDocumentDemo {

    public static void main(String[] args) {

        AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
        DynamoDB docClient = new DynamoDB(client);

        Table table = docClient.getTable("Music");
        GetItemOutcome outcome = table.getItemOutcome(
                "Artist", "No One You Know",
                "SongTitle", "Call Me Today");

        int year = outcome.getItem().getInt("Year");
        System.out.println("The song was released in " + year);

    }
}
```

## DynamoDB에서 작동하는 객체 지속성 인터페이스
<a name="Programming.SDKs.Interfaces.Mapper"></a>

일부 AWS SDK는 직접 데이터 영역 작업을 수행하지 않는 객체 지속성 인터페이스를 제공합니다. 그 대신 Amazon DynamoDB 테이블 및 인덱스의 항목을 나타내는 객체를 생성하고 이러한 객체와 상호 작용합니다. 이를 통해 데이터베이스 중심 코드가 아니라 객체 중심 코드를 만들 수 있습니다.

**참고**  
객체 지속성 인터페이스는 Java 및 .NET용 AWS SDK에서 제공됩니다. 자세한 내용은 DynamoDB의 [DynamoDB에 대한 높은 수준의 프로그래밍 인터페이스](HigherLevelInterfaces.md)를 참조하세요.

### 객체 지속성 인터페이스 예제
<a name="mapper-level-example"></a>

```
import com.example.dynamodb.Customer;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
```

```
import com.example.dynamodb.Customer;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;

/*
 * Before running this code example, create an Amazon DynamoDB table named Customer with these columns:
 *   - id - the id of the record that is the key. Be sure one of the id values is `id101`
 *   - custName - the customer name
 *   - email - the email value
 *   - registrationDate - an instant value when the item was added to the table. These values
 *                        need to be in the form of `YYYY-MM-DDTHH:mm:ssZ`, such as 2022-07-11T00:00:00Z
 *
 * Also, ensure that you have set up your development environment, including your credentials.
 *
 * For information, see this documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */

public class EnhancedGetItem {
    public static void main(String[] args) {
        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

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

        getItem(enhancedClient);
        ddb.close();
    }

    public static String getItem(DynamoDbEnhancedClient enhancedClient) {
        Customer result = null;
        try {
            DynamoDbTable<Customer> table = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
            Key key = Key.builder()
                    .partitionValue("id101").sortValue("tred@noserver.com")
                    .build();

            // Get the item by using the key.
            result = table.getItem(
                    (GetItemEnhancedRequest.Builder requestBuilder) -> requestBuilder.key(key));
            System.out.println("******* The description value is " + result.getCustName());

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        return result.getCustName();
    }
}
```

# DynamoDB에 대한 높은 수준의 프로그래밍 인터페이스
<a name="HigherLevelInterfaces"></a>

AWS SDK는 애플리케이션에 Amazon DynamoDB에서 사용할 수 있는 하위 수준의 인터페이스를 제공합니다. 이러한 클라이언트 측 클래스와 메서드는 하위 수준 DynamoDB API에 직접적으로 대응합니다. 그러나 많은 개발자들이 복잡한 데이터 형식을 데이터베이스 테이블의 항목으로 매핑해야 할 때 연결 끊김 현상, 다시 말해 *임피던스 불일치*를 경험합니다. 하위 수준의 데이터베이스 인터페이스를 사용하는 개발자는 객체 데이터를 읽거나 데이터베이스 테이블에 쓰기 위한 메서드를 작성해야 하며 그 반대의 경우도 마찬가지입니다. 각 객체 유형 및 데이터베이스 테이블 조합에 필요한 추가 코드의 양은 엄청날 수 있습니다.

Java 및 .NET용 AWS SDK는 개발을 간소화하기 위해 높은 수준의 추상화를 갖춘 인터페이스를 추가로 제공합니다. 높은 수준의 DynamoDB 인터페이스를 사용하면 프로그램의 객체와 해당 객체의 데이터를 저장하는 데이터베이스 테이블 간의 관계를 정의할 수 있습니다. 이러한 매핑을 정의한 후 `save`, `load` 또는 `delete`와 같은 간단한 객체 메서드를 호출하면 기본 하위 수준 DynamoDB 작업이 사용자를 대신하여 자동으로 호출됩니다. 이를 통해 데이터베이스 중심 코드가 아니라 객체 중심 코드를 만들 수 있습니다.

높은 수준의 DynamoDB 프로그래밍 인터페이스는 Java 및 .NET용 AWS SDK에서 제공됩니다.

**Java**
+ [Java 1.x: DynamoDBMapper](DynamoDBMapper.md)
+ [Java 2.x: DynamoDB 고급형 클라이언트](DynamoDBEnhanced.md)

**.NET**
+ [DynamoDB에서 .NET 문서 모델을 사용하여 작업](DotNetSDKMidLevel.md)
+ [.NET 객체 지속성 모델 및 DynamoDB로 작업](DotNetSDKHighLevel.md)

# 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)를 참조하시기 바랍니다.

# Java 2.x: DynamoDB 고급형 클라이언트
<a name="DynamoDBEnhanced"></a>

DynamoDB 고급형 클라이언트는 AWS SDK for Java 버전 2(v2)의 일부인 상위 수준 라이브러리로서, 클라이언트 측 클래스를 DynamoDB 테이블에 매핑하는 간단한 방법을 제공합니다. 코드에서 테이블과 해당 모델 클래스 간의 관계를 정의합니다. 이러한 관계를 정의한 다음 DynamoDB의 테이블 또는 항목에 대해 다양한 생성, 읽기, 업데이트 또는 삭제(CRUD) 작업을 직관적으로 수행할 수 있습니다.

고급형 클라이언트를 DynamoDB와 함께 사용하는 방법에 대한 자세한 내용은 [AWS SDK for Java 2.x에서 DynamoDB 고급형 클라이언트 사용](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)을 참조하세요.

# DynamoDB에서 .NET 문서 모델을 사용하여 작업
<a name="DotNetSDKMidLevel"></a>

AWS SDK for .NET은 일부 하위 수준 Amazon DynamoDB 작업을 래핑하여 코딩을 더 간단하게 만드는 문서 모델 클래스를 제공합니다. 이 문서 모델에서 기본 클래스는 `Table` 및 `Document`입니다. `Table` 클래스는 `PutItem`, `GetItem` 및 `DeleteItem`과 같은 데이터 작업 메서드를 제공합니다. 또한 `Query` 및 `Scan` 메서드를 제공합니다. `Document` 클래스는 테이블의 단일 항목을 나타냅니다.

위의 문서 모델 클래스는 `Amazon.DynamoDBv2.DocumentModel` 네임스페이스에서 사용할 수 있습니다.

**참고**  
이 문서 모델 클래스를 사용하여 테이블을 생성, 업데이트 및 삭제할 수 없습니다. 그러나 이 문서 모델은 대부분의 일반적인 데이터 작업을 지원합니다.

**Topics**
+ [지원되는 데이터 유형](#MidLevelAPILimitations.SupportedTypes)

## 지원되는 데이터 유형
<a name="MidLevelAPILimitations.SupportedTypes"></a>

문서 모델은 기본 .NET 데이터 형식 및 컬렉션 데이터 형식 세트를 지원합니다. 모델이 지원하는 기본 데이터 유형은 다음과 같습니다.
+ `bool`
+ `byte` 
+ `char`
+ `DateTime`
+ `decimal`
+ `double`
+ `float`
+ `Guid`
+ `Int16`
+ `Int32`
+ `Int64`
+ `SByte`
+ `string`
+ `UInt16`
+ `UInt32`
+ `UInt64`

다음 표에서는 앞서 나온 .NET 형식을 DynamoDB 형식으로 매핑하는 것을 요약하여 보여 줍니다.


****  

| .NET 기본 유형 | DynamoDB 형식 | 
| --- | --- | 
|  모두 숫자 형식  |  `N`(숫자 형식)  | 
|  모든 문자열 형식  |  `S`(문자열 형식)   | 
|  MemoryStream, byte[]  |  `B`(이진수 형식)   | 
| bool | N(숫자 형식). 0은 false를 나타내고 1은 true를 나타냅니다. | 
| DateTime | S(문자열 형식) DateTime 값은 ISO-8601 형식의 문자열로 저장됩니다. | 
| Guid | S(문자열 형식) | 
| 컬렉션 유형(List, HashSet 및 array) | BS(이진수 세트) 형식, SS(문자열 세트) 형식, 그리고 NS(숫자 세트) 형식 | 

AWS SDK for .NET은 DynamoDB의 부울, null, 목록 및 맵 형식을 .NET 문서 모델 API에 매핑하기 위한 형식을 정의합니다.
+ 부울 형식에 `DynamoDBBool`을 사용합니다.
+ null 형식에 `DynamoDBNull`을 사용합니다.
+ 목록 형식에 `DynamoDBList`를 사용합니다.
+ 맵 형식에 `Document`를 사용합니다.

**참고**  
빈 이진수 값이 지원됩니다.
빈 문자열 값 읽기가 지원됩니다. DynamoDB에 쓰는 동안 문자열 집합 형식의 속성 값에서 빈 문자열 속성 값이 지원됩니다. 문자열 형식의 빈 문자열 속성 값과 목록 또는 맵 형식에 포함된 빈 문자열 값은 쓰기 요청에서 삭제됩니다.

# .NET 객체 지속성 모델 및 DynamoDB로 작업
<a name="DotNetSDKHighLevel"></a>

AWS SDK for .NET은 객체 지속성 모델을 제공하므로 이것으로 클라이언트 측 클래스를 Amazon DynamoDB 테이블에 매핑할 수 있습니다. 그러면 각 객체 인스턴스도 해당 테이블 항목으로 매핑됩니다. 클라이언트 측 객체를 테이블에 저장하기 위해 객체 지속성 모델에서는 DynamoDB에 대한 진입점인 `DynamoDBContext` 클래스를 제공합니다. 이 클래스는 DynamoDB로 연결하는 역할을 하기 때문에 테이블에 액세스하여 다양한 CRUD 작업이 가능할 뿐만 아니라 쿼리를 실행할 수 있습니다.

객체 지속성 모델은 속성 세트를 제공하여 클라이언트 측 클래스를 테이블로 매핑할 수 있으며, 속성/필드를 테이블 속성으로 매핑할 수 있습니다.

**참고**  
객체 지속성 모델은 테이블을 생성, 업데이트 또는 삭제할 수 있는 API를 제공하지 않으며 데이터 작업만 제공합니다. 테이블 생성, 업데이트 및 삭제에는 AWS SDK for .NET 하위 수준 API만 사용할 수 있습니다.

다음 예제에서는 객체 지속성 모델이 작동하는 방법을 보여줍니다. `ProductCatalog` 테이블로 시작합니다. `Id`를 기본 키로 갖고 있습니다.

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

`Book` 클래스를 `Title`, `ISBN` 및 `Authors` 속성과 함께 갖고 있는 경우 다음 C\$1 코드 예제와 같이 객체 지속성 모델로 정의된 속성을 추가하여 `Book` 클래스를 `ProductCatalog` 테이블에 매핑할 수 있습니다.

**Example**  

```
[DynamoDBTable("ProductCatalog")]
  public class Book
  {
    [DynamoDBHashKey]
    public int Id { get; set; }

    public string Title { get; set; }
    public int ISBN { get; set; }

    [DynamoDBProperty("Authors")]
    public List<string> BookAuthors { get; set; }

    [DynamoDBIgnore]
    public string CoverPage { get; set; }
  }
```

앞의 예제에서는 `DynamoDBTable` 속성이 `Book` 클래스를 `ProductCatalog` 테이블에 매핑합니다.

객체 지속성 모델은 클래스 속성 및 테이블 속성 간 명시적 매핑과 기본 매핑 모두를 지원합니다.
+ **명시적 매핑** - 속성을 기본 키에 매핑하려면 `DynamoDBHashKey` 및 `DynamoDBRangeKey` 객체 지속성 모델 속성을 사용해야 합니다. 또한 기본이 아닌 키 속성의 경우 클래스의 속성 이름과 이를 매핑하려는 해당 테이블 속성이 같지 않다면 `DynamoDBProperty` 속성을 명시적으로 추가하여 매핑을 정의해야 합니다.

  앞의 예제에서는 `Id` 속성이 같은 이름의 기본 키로 매핑되고 `BookAuthors` 속성이 `Authors` 테이블의 `ProductCatalog` 속성으로 매핑됩니다.
+ **기본 매핑** - 기본적으로 객체 지속성 모델은 클래스 속성을 같은 이름의 테이블 속성으로 매핑합니다.

  앞의 예제에서는 `Title` 및 `ISBN` 속성이 `ProductCatalog` 테이블에 있는 같은 이름의 속성으로 매핑됩니다.

각 클래스 속성을 전부 하나씩 매핑할 필요는 없습니다. `DynamoDBIgnore` 속성을 추가하여 이러한 속성을 확인할 수 있습니다. `Book` 인스턴스를 테이블에 저장하더라도 `DynamoDBContext`에는 `CoverPage` 속성이 포함되지 않습니다. 또한 이러한 책 인스턴스를 가져와도 이 속성은 반환되지 않습니다.

int 및 문자열과 같은 .NET 기본 유형의 속성을 매핑할 수 있습니다. 적절한 변환기를 사용하여 임의 데이터를 DynamoDB 형식 중 하나로 매핑만 한다면 어떤 임의 데이터 형식도 매핑할 수 있습니다. 임의 유형 매핑에 대한 자세한 내용은 [AWS SDK for .NET 객체 지속성 모델을 사용하여 DynamoDB에서 임의 데이터 매핑](DynamoDBContext.ArbitraryDataMapping.md) 단원을 참조하세요.

객체 지속성 모델은 낙관적 잠금을 지원합니다. 따라서 업데이트 작업 동안 업데이트하려는 항목의 최신 복사본을 가질 수 있습니다. 자세한 내용은 [DynamoDB 및 AWS SDK for .NET 객체 지속성 모델을 사용하여 낙관적 잠금 수행](DynamoDBContext.VersionSupport.md) 섹션을 참조하세요.

자세한 내용은 아래 주제를 참조하십시오.

**Topics**
+ [지원되는 데이터 유형](#DotNetDynamoDBContext.SupportedTypes)
+ [.NET 객체 지속성 모델의 DynamoDB 속성](DeclarativeTagsList.md)
+ [.NET 객체 지속성 모델의 DynamoDBContext 클래스](DotNetDynamoDBContext.md)
+ [DynamoDB 및 AWS SDK for .NET 객체 지속성 모델을 사용하여 낙관적 잠금 수행](DynamoDBContext.VersionSupport.md)
+ [AWS SDK for .NET 객체 지속성 모델을 사용하여 DynamoDB에서 임의 데이터 매핑](DynamoDBContext.ArbitraryDataMapping.md)

## 지원되는 데이터 유형
<a name="DotNetDynamoDBContext.SupportedTypes"></a>

객체 지속성 모델은 기본 .NET 데이터 유형 세트와 컬렉션, 그리고 임의 데이터 유형을 지원합니다. 모델이 지원하는 기본 데이터 유형은 다음과 같습니다.
+ `bool`
+ `byte` 
+ `char`
+ `DateTime`
+ `decimal`
+ `double`
+ `float`
+ `Int16`
+ `Int32`
+ `Int64`
+ `SByte`
+ `string`
+ `UInt16`
+ `UInt32`
+ `UInt64`

객체 지속성 모델은 .NET 컬렉션 형식도 지원합니다. `DynamoDBContext`는 구체적인 컬렉션 형식과 단순한 POCO(Plain Old CLR Object)를 변환할 수 있습니다.

다음 표에서는 앞서 나온 .NET 형식을 DynamoDB 형식으로 매핑하는 것을 요약하여 보여 줍니다.


****  

| .NET 기본 유형 | DynamoDB 형식 | 
| --- | --- | 
|  모두 숫자 형식  |  `N`(숫자 형식)  | 
|  모든 문자열 형식  |  `S`(문자열 형식)   | 
|  MemoryStream, byte[]  |  `B`(이진수 형식)   | 
| bool | N(숫자 형식). 0은 false를 나타내고 1은 true를 나타냅니다. | 
| 컬렉션 유형 | BS(이진수 세트) 형식, SS(문자열 세트) 형식, 그리고 NS(숫자 세트) 형식 | 
| DateTime | S(문자열 형식) DateTime 값은 ISO-8601 형식의 문자열로 저장됩니다. | 

객체 지속성 모델은 임의 데이터 형식 또한 지원합니다. 하지만 여러 형식을 DynamoDB 형식으로 매핑하려면 변환기 코드를 입력해야 합니다.

**참고**  
빈 이진수 값이 지원됩니다.
빈 문자열 값 읽기가 지원됩니다. DynamoDB에 쓰는 동안 문자열 집합 형식의 속성 값에서 빈 문자열 속성 값이 지원됩니다. 문자열 형식의 빈 문자열 속성 값과 목록 또는 맵 형식에 포함된 빈 문자열 값은 쓰기 요청에서 삭제됩니다.

# .NET 객체 지속성 모델의 DynamoDB 속성
<a name="DeclarativeTagsList"></a>

이 단원에서는 사용자가 클래스 및 속성을 DynamoDB 테이블 및 속성으로 매핑할 수 있도록 객체 지속성 모델이 제공하는 속성에 대해 설명합니다.

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

## DynamoDBGlobalSecondaryIndexHashKey
<a name="w2aac17b9c21c23c37b7"></a>

클래스 속성을 글로벌 보조 인텍스의 파티션 키로 매핑합니다. 이 속성은 글로벌 보조 인덱스를 `Query`해야 하는 경우 사용합니다.

## DynamoDBGlobalSecondaryIndexRangeKey
<a name="w2aac17b9c21c23c37b9"></a>

클래스 속성을 글로벌 보조 인텍스의 정렬 키로 매핑합니다. 이 속성은 글로벌 보조 인덱스를 `Query`해야 하거나 인덱스 정렬 키를 사용하여 결과를 구체화하고 싶은 경우에 사용합니다.

## DynamoDBHashKey
<a name="w2aac17b9c21c23c37c11"></a>

클래스 속성을 테이블의 기본 키 파티션 키로 매핑합니다. 기본 키 속성은 컬렉션 형식이 될 수 없습니다.

다음 C\$1 코드 예제에서는 `Book` 클래스를 `ProductCatalog` 테이블로 매핑하고, `Id` 속성을 테이블의 기본 키 파티션 키로 매핑합니다.

```
[DynamoDBTable("ProductCatalog")]
public class Book 
{
    [DynamoDBHashKey]
    public int Id { get; set; }

    // Additional properties go here.
}
```

## DynamoDBIgnore
<a name="w2aac17b9c21c23c37c13"></a>

연결된 속성을 무시해야 함을 나타냅니다. 어떠한 클래스 속성도 저장하지 않으려면 이 속성을 추가하여 `DynamoDBContext`가 객체를 테이블에 저장할 때 이 속성을 포함하지 않도록 지시할 수 있습니다.

## DynamoDBLocalSecondaryIndexRangeKey
<a name="w2aac17b9c21c23c37c15"></a>

클래스 속성을 로컬 보조 인텍스의 정렬 키로 매핑합니다. 이 속성은 로컬 보조 인덱스를 `Query`해야 하거나 인덱스 정렬 키를 사용하여 결과를 구체화하고 싶은 경우에 사용합니다.

## DynamoDBProperty
<a name="w2aac17b9c21c23c37c17"></a>

클래스 속성을 테이블 속성으로 매핑합니다. 클래스 속성을 같은 이름의 테이블 속성으로 매핑할 경우에는 이 속성을 지정할 필요가 없습니다. 하지만 이름이 다를 경우에는 매핑을 제공하는 데 이 태그를 사용할 수 있습니다. 다음 C\$1 문에서는 `DynamoDBProperty`가 `BookAuthors` 속성을 테이블의 `Authors` 속성으로 매핑합니다.

```
[DynamoDBProperty("Authors")]
public List<string> BookAuthors { get; set; }
```

`DynamoDBContext`는 객체 데이터를 해당 테이블에 저장할 때 이 매핑 정보를 사용하여 `Authors` 속성을 생성합니다.

## DynamoDBRenamable
<a name="w2aac17b9c21c23c37c19"></a>

클래스 속성의 대체 이름을 지정합니다. 이것은 클래스 속성 이름이 테이블 속성과 다른 DynamoDB 테이블로 임의 데이터를 매핑하기 위한 사용자 지정 변환기를 쓰고 있을 때 유용합니다.

## DynamoDBRangeKey
<a name="w2aac17b9c21c23c37c21"></a>

클래스 속성을 테이블의 기본 키 정렬 키로 매핑합니다. 테이블에 복합 기본 키(파티션 키 및 정렬 키)가 있는 경우 클래스 매핑에서 `DynamoDBHashKey` 속성과 `DynamoDBRangeKey` 속성을 모두 지정해야 합니다.

예를 들어, 샘플 테이블 `Reply`에는 `Id` 파티션 키 및 `Replenishment` 정렬 키로 구성된 기본 키가 있습니다. 다음 C\$1 코드 예제에서는 `Reply` 클래스를 `Reply` 테이블로 매핑합니다. 클래스 정의는 또한 그 속성 중 두 가지를 기본 키로 매핑하도록 지시합니다.

```
[DynamoDBTable("Reply")]
public class Reply 
{
   [DynamoDBHashKey]
   public int ThreadId { get; set; }
   [DynamoDBRangeKey]
   public string Replenishment { get; set; }
   
   // Additional properties go here.
}
```

## DynamoDBTable
<a name="w2aac17b9c21c23c37c23"></a>

클래스가 매핑하는 대상으로 DynamoDB의 대상 테이블을 식별합니다. 예를 들어, 다음 C\$1 코드 예제에서는 `Developer` 클래스를 DynamoDB의 `People` 테이블로 매핑합니다.

```
[DynamoDBTable("People")]
public class Developer { ...}
```

이 속성은 상속 또는 재정의될 수 있습니다.
+ `DynamoDBTable` 속성은 상속될 수 있습니다. 앞의 예제에서는 `Lead` 클래스에서 상속된 새 클래스 `Developer`를 추가하는 경우 해당 클래스도 `People` 테이블에도 매핑됩니다. `Developer` 객체와 `Lead` 객체 모두 `People` 테이블에 저장됩니다.
+ `DynamoDBTable` 속성 또한 재정의될 수 있습니다. 다음 C\$1 코드 예제에서는 `Manager` 클래스가 `Developer` 클래스에서 상속됩니다. 그러나 `DynamoDBTable` 속성을 명시적으로 추가하면 이 클래스가 다른 테이블(`Managers`)로 매핑됩니다.

  ```
  [DynamoDBTable("Managers")]
  public class Manager : Developer { ...}
  ```

 다음 C\$1 코드 예제와 같이 테이블에 객체를 저장할 때 선택적 파라미터인 `LowerCamelCaseProperties`를 추가하면 속성 이름의 첫 번째 글자를 소문자로 만들도록 DynamoDB에 요청할 수 있습니다.

```
[DynamoDBTable("People", LowerCamelCaseProperties=true)]
public class Developer 
{
    string DeveloperName;
    ...
}
```

`Developer` 클래스의 인스턴스를 저장할 때 `DynamoDBContext`가 `DeveloperName` 속성을 `developerName`으로 저장합니다.

## DynamoDBVersion
<a name="w2aac17b9c21c23c37c25"></a>

항목 버전 번호를 저장하는 클래스 속성을 식별합니다. 버전 관리에 대한 자세한 내용은 [DynamoDB 및 AWS SDK for .NET 객체 지속성 모델을 사용하여 낙관적 잠금 수행](DynamoDBContext.VersionSupport.md) 섹션을 참조하십시오.

# .NET 객체 지속성 모델의 DynamoDBContext 클래스
<a name="DotNetDynamoDBContext"></a>

`DynamoDBContext` 클래스는 Amazon DynamoDB 데이터베이스의 진입점입니다. 이 클래스는 DynamoDB로의 연결을 제공하며, 데이터를 다양한 테이블에 액세스하고 다양한 CRUD 작업을 수행하며 쿼리를 실행할 수 있게 합니다. `DynamoDBContext` 클래스는 다음과 같은 메서드를 제공합니다.

**Topics**
+ [Create​MultiTable​BatchGet](#w2aac17b9c21c23c39b7)
+ [Create​MultiTable​BatchWrite](#w2aac17b9c21c23c39b9)
+ [CreateBatchGet](#w2aac17b9c21c23c39c11)
+ [CreateBatchWrite](#w2aac17b9c21c23c39c13)
+ [삭제](#w2aac17b9c21c23c39c15)
+ [Dispose](#w2aac17b9c21c23c39c17)
+ [Execute​Batch​Get](#w2aac17b9c21c23c39c19)
+ [Execute​Batch​Write](#w2aac17b9c21c23c39c21)
+ [FromDocument](#w2aac17b9c21c23c39c23)
+ [FromQuery](#w2aac17b9c21c23c39c25)
+ [FromScan](#w2aac17b9c21c23c39c27)
+ [Get​Target​Table](#w2aac17b9c21c23c39c29)
+ [Load](#w2aac17b9c21c23c39c31)
+ [쿼리](#w2aac17b9c21c23c39c33)
+ [Save](#w2aac17b9c21c23c39c35)
+ [스캔](#w2aac17b9c21c23c39c37)
+ [ToDocument](#w2aac17b9c21c23c39c39)
+ [DynamoDBContext에 대한 옵션 파라미터 지정](#OptionalConfigParams)

## Create​MultiTable​BatchGet
<a name="w2aac17b9c21c23c39b7"></a>

여러 개의 개별 `MultiTableBatchGet` 객체로 구성된 `BatchGet` 객체를 만듭니다. 이러한 `BatchGet` 객체 각각은 단일 DynamoDB 테이블에서 항목을 가져오는 데 사용됩니다.

테이블에서 항목을 검색하려면 `ExecuteBatchGet` 메서드를 사용하여 `MultiTableBatchGet` 객체를 파라미터로 전달합니다.

## Create​MultiTable​BatchWrite
<a name="w2aac17b9c21c23c39b9"></a>

여러 개의 개별 `MultiTableBatchWrite` 객체로 구성된 `BatchWrite` 객체를 만듭니다. 이러한 `BatchWrite` 객체 각각은 단일 DynamoDB 테이블에서 항목을 쓰거나 삭제하는 데 사용됩니다.

테이블에 쓰려면 `ExecuteBatchWrite` 메서드를 사용하여 `MultiTableBatchWrite` 객체를 파라미터로 전달합니다.

## CreateBatchGet
<a name="w2aac17b9c21c23c39c11"></a>

`BatchGet` 객체를 만들어 테이블에서 여러 개의 항목을 가져올 수 있습니다.

## CreateBatchWrite
<a name="w2aac17b9c21c23c39c13"></a>

`BatchWrite` 객체를 만들어 여러 개의 항목을 테이블에 넣는 데 사용하거나 테이블에서 여러 개의 항목을 삭제하는 데 사용할 수 있습니다.

## 삭제
<a name="w2aac17b9c21c23c39c15"></a>

항목을 테이블에서 삭제합니다. 메서드에는 삭제하려는 항목의 기본 키가 필요합니다. 기본 키 값 또는 기본 키 값을 포함하는 클라이언트 측 객체 중 한 가지를 파라미터로 이 메서드에 제공할 수 있습니다.
+ 클라이언트 측 객체를 파라미터로 지정하고 낙관적 잠금을 활성화했다면, 클라이언트 측과 객체의 서버 쪽 버전이 일치해야만 삭제가 성공적으로 이루어집니다.
+ 기본 키 값만을 파라미터로 지정한 경우, 낙관적 잠금을 활성화했는지의 여부와 상관없이 삭제가 성공적으로 이루어집니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `DeleteAsync` 메서드를 대신 사용하세요.

## Dispose
<a name="w2aac17b9c21c23c39c17"></a>

관리되거나 관리되지 않는 리소스를 모두 일괄합니다.

## Execute​Batch​Get
<a name="w2aac17b9c21c23c39c19"></a>

모든 `BatchGet` 객체를 `MultiTableBatchGet`에서 처리하여, 하나 또는 그 이상의 테이블에서 데이터를 읽습니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `ExecuteBatchGetAsync` 메서드를 대신 사용하세요.

## Execute​Batch​Write
<a name="w2aac17b9c21c23c39c21"></a>

모든 `BatchWrite` 객체를 `MultiTableBatchWrite`에서 처리하여, 하나 또는 그 이상의 테이블에 데이터를 쓰거나 삭제합니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `ExecuteBatchWriteAsync` 메서드를 대신 사용하세요.

## FromDocument
<a name="w2aac17b9c21c23c39c23"></a>

할당된 `Document` 인스턴스에서 `FromDocument` 메서드가 클라이언트 측 클래스의 인스턴스를 반환합니다.

이것은 문서 모델 클래스를 객체 지속성 모델과 함께 사용하여 데이터 작업을 수행할 때 유용합니다. AWS SDK for .NET에 의해 제공되는 문서 모델 클래스에 대한 자세한 내용은 [DynamoDB에서 .NET 문서 모델을 사용하여 작업](DotNetSDKMidLevel.md) 단원을 참조하세요.

`Document` 항목 표시 정보를 포함하는 `doc`라는 이름의 `Forum` 객체가 있는 경우 (이 객체를 구성하는 방법은 이 주제의 후반부에 있는 `ToDocument` 메서드 설명을 참조하세요.) 다음 C\$1 코드 예제와 같이 `FromDocument`를 사용하여 `Forum`에서 `Document` 항목을 검색할 수 있습니다.

**Example**  

```
forum101 = context.FromDocument<Forum>(101);
```

**참고**  
`Document` 객체가 `IEnumerable` 인터페이스를 구현하는 경우에는 `FromDocuments` 메서드를 대신 사용할 수 있습니다. 그러면 `Document`에서 모든 클래스 인스턴스를 반복적으로 처리할 수 있습니다.

## FromQuery
<a name="w2aac17b9c21c23c39c25"></a>

`QueryOperationConfig` 객체에 정의된 쿼리 파라미터로 `Query` 작업을 실행합니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `FromQueryAsync` 메서드를 대신 사용하세요.

## FromScan
<a name="w2aac17b9c21c23c39c27"></a>

`ScanOperationConfig` 객체에 정의된 스캔 파라미터로 `Scan` 작업을 실행합니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `FromScanAsync` 메서드를 대신 사용하세요.

## Get​Target​Table
<a name="w2aac17b9c21c23c39c29"></a>

지정된 유형에 대한 대상 테이블을 가져옵니다. 이는 임의 데이터를 DynamoDB 테이블로 매핑하기 위한 사용자 지정 변환기를 작성하고 사용자 지정 데이터 형식과 연결되는 테이블을 확인해야 할 때 유용합니다.

## Load
<a name="w2aac17b9c21c23c39c31"></a>

테이블에서 항목을 가져옵니다. 이 메서드에는 가져오려는 항목의 기본 키만 필요합니다.

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

`Load` 또는 `LoadAsync` 메서드는 [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) 작업을 직접 호출합니다. 이 작업을 수행하려면 테이블의 프라이머리 키를 지정해야 합니다. `GetItem`에서는 `IndexName` 파라미터를 무시하므로, 인덱스의 파티션 또는 정렬 키를 사용하여 항목을 로드할 수 없습니다. 따라서 테이블의 프라이머리 키를 사용하여 항목을 로드해야 합니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `LoadAsync` 메서드를 대신 사용하세요. `LoadAsync` 메서드를 사용하여 DynamoDB 테이블에서 상위 수준의 CRUD 작업을 수행하는 예제를 보려면 다음 예제를 참조하세요.

```
    /// <summary>
    /// Shows how to perform high-level CRUD operations on an Amazon DynamoDB
    /// table.
    /// </summary>
    public class HighLevelItemCrud
    {
        public static async Task Main()
        {
            var client = new AmazonDynamoDBClient();
            DynamoDBContext context = new DynamoDBContext(client);
            await PerformCRUDOperations(context);
        }

        public static async Task PerformCRUDOperations(IDynamoDBContext context)
        {
            int bookId = 1001; // Some unique value.
            Book myBook = new Book
            {
                Id = bookId,
                Title = "object persistence-AWS SDK for.NET SDK-Book 1001",
                Isbn = "111-1111111001",
                BookAuthors = new List<string> { "Author 1", "Author 2" },
            };

            // Save the book to the ProductCatalog table.
            await context.SaveAsync(myBook);

            // Retrieve the book from the ProductCatalog table.
            Book bookRetrieved = await context.LoadAsync<Book>(bookId);

            // Update some properties.
            bookRetrieved.Isbn = "222-2222221001";

            // Update existing authors list with the following values.
            bookRetrieved.BookAuthors = new List<string> { " Author 1", "Author x" };
            await context.SaveAsync(bookRetrieved);

            // Retrieve the updated book. This time, add the optional
            // ConsistentRead parameter using DynamoDBContextConfig object.
            await context.LoadAsync<Book>(bookId, new DynamoDBContextConfig
            {
                ConsistentRead = true,
            });

            // Delete the book.
            await context.DeleteAsync<Book>(bookId);

            // Try to retrieve deleted book. It should return null.
            Book deletedBook = await context.LoadAsync<Book>(bookId, new DynamoDBContextConfig
            {
                ConsistentRead = true,
            });

            if (deletedBook == null)
            {
                Console.WriteLine("Book is deleted");
            }
        }
    }
```

## 쿼리
<a name="w2aac17b9c21c23c39c33"></a>

입력하는 쿼리 파라미터를 기반으로 테이블을 쿼리합니다.

테이블에 복합 기본 키(파티션 키 및 정렬 키)가 있는 경우에만 테이블을 쿼리할 수 있습니다. 쿼리 시에는 파티션 키를 비롯하여 정렬 키에 적용되는 조건을 지정해야 합니다.

DynamoDB의 `Reply` 테이블에 클라이언트 측 `Reply` 클래스가 매핑되어 있는 경우 다음 C\$1 코드 예제에서는 과거 15일 간 게시된 포럼 스레드 회신을 찾기 위해 `Reply` 테이블을 쿼리합니다. `Reply` 테이블에는 `Id` 파티션 키와 `ReplyDateTime` 정렬 키로 구성된 기본 키가 있습니다.

**Example**  

```
DynamoDBContext context = new DynamoDBContext(client);

string replyId = "DynamoDB#DynamoDB Thread 1"; //Partition key
DateTime twoWeeksAgoDate = DateTime.UtcNow.Subtract(new TimeSpan(14, 0, 0, 0)); // Date to compare.
IEnumerable<Reply> latestReplies = context.Query<Reply>(replyId, QueryOperator.GreaterThan, twoWeeksAgoDate);
```

이를 통해 `Reply` 객체 컬렉션이 반환됩니다.

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

테이블에 단순 기본 키(파티션 키)가 있는 경우에는 `Query` 메서드를 사용할 수 없습니다. 대신 `Load` 메서드를 사용하면 파티션 키를 입력하여 항목을 가져올 수 있습니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `QueryAsync` 메서드를 대신 사용하세요.

## Save
<a name="w2aac17b9c21c23c39c35"></a>

지정한 객체를 테이블에 저장합니다. 입력 객체에 지정된 기본 키가 테이블에 존재하지 않는 경우 메서드가 테이블에 새 항목을 추가합니다. 기본 키가 있는 경우 메서드가 기존 항목을 업데이트합니다.

낙관적 잠금이 구성된 경우 항목의 서버 측 버전과 클라이언트 측 버전이 일치하는 경우에만 업데이트가 성공합니다. 자세한 내용은 [DynamoDB 및 AWS SDK for .NET 객체 지속성 모델을 사용하여 낙관적 잠금 수행](DynamoDBContext.VersionSupport.md) 섹션을 참조하세요.

**참고**  
백그라운드에서 이 작업을 수행하려면 `SaveAsync` 메서드를 대신 사용하세요.

## 스캔
<a name="w2aac17b9c21c23c39c37"></a>

전체 테이블 스캔을 수행합니다.

스캔 조건을 지정하여 스캔 결과를 필터링할 수 있습니다. 스캔 조건은 테이블의 어느 속성 상에서든지 평가될 수 있습니다. DynamoDB의 `ProductCatalog` 테이블에 클라이언트 측 `Book` 클래스가 매핑되어 있는 경우 다음 C\$1 코드 예제에서는 테이블을 스캔하고 가격이 0보다 작은 책 항목만 반환합니다.

**Example**  

```
IEnumerable<Book> itemsWithWrongPrice = context.Scan<Book>(
                    new ScanCondition("Price", ScanOperator.LessThan, price),
                    new ScanCondition("ProductCategory", ScanOperator.Equal, "Book")
      );
```

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

성능 문제 때문에 테이블 스캔을 피하고 테이블을 쿼리해야 합니다.

**참고**  
백그라운드에서 이 작업을 수행하려면 `ScanAsync` 메서드를 대신 사용하세요.

## ToDocument
<a name="w2aac17b9c21c23c39c39"></a>

클래스 인스턴스에서 `Document` 문서 모델 클래스의 인스턴스가 반환됩니다.

이것은 문서 모델 클래스를 객체 지속성 모델과 함께 사용하여 데이터 작업을 수행할 때 유용합니다. AWS SDK for .NET에 의해 제공되는 문서 모델 클래스에 대한 자세한 내용은 [DynamoDB에서 .NET 문서 모델을 사용하여 작업](DotNetSDKMidLevel.md) 단원을 참조하세요.

샘플 `Forum` 테이블에 클라이언트 측 클래스가 매핑되어 있는 경우 다음 C\$1 코드 예제와 같이 `DynamoDBContext`를 사용하여 `Document` 테이블에서 항목을 `Forum` 객체로 얻을 수 있습니다.

**Example**  

```
DynamoDBContext context = new DynamoDBContext(client);

Forum forum101 = context.Load<Forum>(101); // Retrieve a forum by primary key.
Document doc = context.ToDocument<Forum>(forum101);
```

## DynamoDBContext에 대한 옵션 파라미터 지정
<a name="OptionalConfigParams"></a>

객체 지속성 모델을 사용하는 경우, `DynamoDBContext`에 대하여 다음과 같은 선택적 파라미터를 지정할 수 있습니다.
+ **`ConsistentRead`** - `Load`, `Query` 또는 `Scan` 작업을 사용하여 데이터를 검색할 때 이 선택적 파라미터를 추가하여 데이터의 최신 값을 요청할 수 있습니다.
+ **`IgnoreNullValues`** - 이 파라미터는 `DynamoDBContext`에 `Save` 작업 동안 속성의 null 값을 무시하도록 지시합니다. 이 파라미터가 false이거나 설정되지 않은 경우 null 값은 특정 속성을 삭제하라는 지시로 해석됩니다.
+ **`SkipVersionCheck`** - 이 파라미터는 항목을 저장하거나 삭제할 때 `DynamoDBContext`에 버전을 비교하지 않도록 지시합니다. 버전 관리에 대한 자세한 내용은 [DynamoDB 및 AWS SDK for .NET 객체 지속성 모델을 사용하여 낙관적 잠금 수행](DynamoDBContext.VersionSupport.md) 섹션을 참조하십시오.
+ ** `TableNamePrefix` **-모든 테이블 이름에서 특정 문자열을 접두사로 사용합니다. 이 파라미터가 null이거나 설정되지 않은 경우, 어떤 접두사도 사용되지 않습니다.
+ `DynamoDBEntryConversion` - 클라이언트가 사용하는 변환 스키마를 지정합니다. 이 파라미터를 버전 V1 또는 V2로 설정할 수 있습니다. 기본 버전은 V1입니다.

  설정한 버전에 따라 이 파라미터의 동작이 달라집니다. 예제:
  + V1에서는 `bool` 데이터 형식이 `N` 숫자 형식으로 변환됩니다. 여기서 0은 false, 1은 true를 나타냅니다. V2에서는 `bool`이 `BOOL`로 변환됩니다.
  + V2에서는 목록과 배열이 HashSet과 함께 그룹화되지 않습니다. 숫자로 구성된 목록과 배열, 문자열 기반 형식, 이진 기반 형식은 `L`(목록) 형식으로 변환됩니다. 이 형식은 목록을 업데이트하기 위해 빈 상태로 보낼 수 있습니다. 이는 빈 목록이 유선으로 전송되지 않는 V1과는 다릅니다.

    V1에서는 목록, HashSet 및 배열과 같은 컬렉션 형식이 동일하게 취급됩니다. 숫자 목록, HashSet 및 배열은 `NS`(숫자 집합) 형식으로 변환됩니다.

  다음 예제에서는 변환 스키마 버전을 V2로 설정하여 .NET 형식과 DynamoDB 데이터 형식 간의 변환 동작을 변경합니다.

  ```
  var config = new DynamoDBContextConfig
  {
      Conversion = DynamoDBEntryConversion.V2
  };
  var contextV2 = new DynamoDBContext(client, config);
  ```

다음 C\$1 예제에서는 앞에 나온 선택적 파라미터 중 두 개인 `ConsistentRead` 및 `SkipVersionCheck`를 지정하여 새 `DynamoDBContext`를 생성합니다.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
...
DynamoDBContext context =
       new DynamoDBContext(client, new DynamoDBContextConfig { ConsistentRead = true, SkipVersionCheck = true});
```

`DynamoDBContext`에는 이 컨텍스트를 사용하여 보내는 각 요청과 함께 이러한 선택적 파라미터가 포함되어 있습니다.

이러한 파라미터를 `DynamoDBContext` 수준에 설정하는 대신 다음 C\$1 코드 예제와 같이 `DynamoDBContext`를 사용하여 실행하는 개별 작업에 대해 이러한 파라미터를 지정할 수 있습니다. 이 예제는 특정 책 항목을 로드합니다. `DynamoDBContext`의 `Load` 메서드는 선택적 파라미터인 `ConsistentRead` 및 `SkipVersionCheck`를 지정합니다.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
...
DynamoDBContext context = new DynamoDBContext(client);
Book bookItem = context.Load<Book>(productId,new DynamoDBContextConfig{ ConsistentRead = true, SkipVersionCheck = true });
```

이 경우 `DynamoDBContext`에는 `Get` 요청을 보내는 경우에 한하여 이러한 파라미터가 포함됩니다.

# DynamoDB 및 AWS SDK for .NET 객체 지속성 모델을 사용하여 낙관적 잠금 수행
<a name="DynamoDBContext.VersionSupport"></a>

객체 지속성 모델의 낙관적 잠금 지원을 통해 항목을 업데이트하거나 삭제하기 전에 애플리케이션에 대한 항목 버전과 서버 측 항목 버전이 동일해집니다. 업데이트할 항목을 검색하는 경우 그러나 업데이트를 돌려보내기 전에 다른 애플리케이션이 같은 항목을 업데이트했습니다. 이 경우, 애플리케이션 항목의 오래된 복사본이 남게 됩니다. 낙관적 잠금이 없는 경우, 업데이트를 수행하면 다른 애플리케이션에 의해 생성된 업데이트를 덮어씁니다.

객체 지속성 모델의 낙관적 잠금 기능은 낙관적 잠금을 활성화하는 데 사용할 수 있는 `DynamoDBVersion` 태그를 제공합니다. 이 기능을 사용하려면 버전 번호를 저장하기 위해 클래스에 속성을 추가합니다. 이 속성에 `DynamoDBVersion` 속성을 추가합니다. 처음 객체를 저장할 때 `DynamoDBContext`가 버전 번호를 할당하고, 항목이 업데이트될 때마다 이 값을 증가시킵니다.

업데이트나 삭제 요청은 클라이언트 측 객체 버전이 서버 측의 해당 항목 버전 번호와 일치해야만 성공합니다. 애플리케이션에 오래된 사본이 있는 경우에는 서버에서 최신 버전을 받아야만 항목을 업데이트하거나 삭제할 수 있습니다.

다음 C\$1 코드 예제에서는 객체 지속성 속성으로 `Book` 클래스를 정의하며 해당 클래스를 `ProductCatalog` 테이블로 매핑합니다. `VersionNumber` 속성이 데코레이트된 클래스의`DynamoDBVersion` 속성에는 버전 번호 값이 저장됩니다.

**Example**  

```
[DynamoDBTable("ProductCatalog")]
  public class Book
  {
    [DynamoDBHashKey]   //Partition key
    public int Id { get; set; }
    [DynamoDBProperty]
    public string Title { get; set; }
    [DynamoDBProperty]
    public string ISBN { get; set; }
    [DynamoDBProperty("Authors")]
    public List<string> BookAuthors { get; set; }
    [DynamoDBVersion]
    public int? VersionNumber { get; set; }
  }
```

**참고**  
`DynamoDBVersion` 속성은 `int?`와 같이 null이 허용된 숫자 기본 유형으로만 적용 가능합니다.

낙관적 잠금 전략은 `DynamoDBContext` 작업에 다음과 같은 영향을 끼칩니다.
+ 새로운 항목이 있을 경우, `DynamoDBContext`는 초기 버전 번호를 0으로 할당합니다. 이후 기존 항목을 검색하고 해당 속성을 하나 이상 업데이트한 후 변경 사항을 저장하려고 해도 클라이언트 측 버전 번호와 서버 측 버전 번호가 일치해야만 저장 작업이 성공합니다. `DynamoDBContext`는 버전 번호를 증가시킵니다. 버전 번호를 설정할 필요는 없습니다.
+ 다음 C\$1 코드 예제와 같이 `Delete` 메서드는 기본 키 값 또는 객체를 파라미터로 사용할 수 있는 오버로드를 제공합니다.  
**Example**  

  ```
  DynamoDBContext context = new DynamoDBContext(client);
  ...
  // Load a book.
  Book book = context.Load<ProductCatalog>(111);
  // Do other operations.
  // Delete 1 - Pass in the book object.
  context.Delete<ProductCatalog>(book);
  
  // Delete 2 - Pass in the Id (primary key)
  context.Delete<ProductCatalog>(222);
  ```

  객체를 파라미터로 제공하는 경우 객체 버전이 서버 측 해당 항목 버전과 일치해야만 삭제가 성공합니다. 그러나 기본 키 값을 파라미터로 제공하는 경우 `DynamoDBContext`는 어떤 버전 번호도 알 수 없으며 버전 확인 없이 항목을 삭제합니다.

  단, 낙관적 잠금을 객체 지속성 모델 코드로 내부 구현할 경우에는 DynamoDB의 조건부 업데이트와 조건부 API 작업 삭제를 사용합니다.

## 낙관적 잠금 비활성화
<a name="DotNetDynamoDBContext.DisablingOptimisticLocking"></a>

낙관적 잠금을 비활성화하려면 `SkipVersionCheck` 구성 속성을 사용합니다. `DynamoDBContext`를 만들 때 이 속성을 설정할 수 있습니다. 이 경우 컨텍스트를 사용하여 수행하는 모든 요청에 대해 낙관적 잠금이 비활성화됩니다. 자세한 내용은 [DynamoDBContext에 대한 옵션 파라미터 지정](DotNetDynamoDBContext.md#OptionalConfigParams) 섹션을 참조하세요.

속성을 컨텍스트 수준에 설정하는 대신 다음 C\$1 코드 예제와 같이 특정 작업에 대한 낙관적 잠금을 비활성화할 수 있습니다. 이 예제에서는 컨텍스트를 사용하여 책 항목을 삭제합니다. `Delete` 메서드는 선택적 `SkipVersionCheck` 속성을 true로 설정하여 버전 확인을 비활성화합니다.

**Example**  

```
DynamoDBContext context = new DynamoDBContext(client);
// Load a book.
Book book = context.Load<ProductCatalog>(111);
...
// Delete the book.
context.Delete<Book>(book, new DynamoDBContextConfig { SkipVersionCheck = true });
```

# AWS SDK for .NET 객체 지속성 모델을 사용하여 DynamoDB에서 임의 데이터 매핑
<a name="DynamoDBContext.ArbitraryDataMapping"></a>

지원되는 .NET 형식([지원되는 데이터 유형](DotNetSDKHighLevel.md#DotNetDynamoDBContext.SupportedTypes) 참조) 외에도 애플리케이션에서 직접적으로 Amazon DynamoDB 형식에 매핑되지 않는 형식을 사용할 수 있습니다. 데이터를 임의 형식에서 DynamoDB 형식으로 또는 그 반대로 변환할 수 있는 변환기가 있는 한 객체 지속성 모델은 임의 형식의 데이터 저장을 지원합니다. 객체를 저장하거나 로드하는 동안 변환기 코드가 데이터를 변환합니다.

클라이언트 측에서 어떤 유형도 생성할 수 있습니다. 그러나 테이블에 저장되는 데이터는 DynamoDB 형식 중 하나이며 쿼리 및 스캔이 진행되는 동안 DynamoDB에 저장되어 있는 데이터에 대해 데이터 비교가 수행됩니다.

다음의 C\$1 코드 예제에서는 `Book`, `Id`, `Title` 및 `ISBN` 속성을 사용하여 `Dimension` 클래스를 정의하고 있습니다. `Dimension` 속성은 `DimensionType`, `Height` 및 `Width` 속성을 기술하는 `Thickness`에 포함되어 있습니다. 이 예제 코드는 데이터를 `DimensionType` 및 DynamoDB 문자열 형식 간에 전환하는 변환기 메서드 `ToEntry` 및 `FromEntry`를 제공합니다. 예를 들어, `Book` 인스턴스를 저장할 때 변환기는 "8.5x11x.05"와 같은 책 `Dimension` 문자열을 생성합니다. 책을 검색하면 문자열이 `DimensionType` 인스턴스로 변환됩니다.

이 예제에서는 `Book` 유형을 `ProductCatalog` 테이블로 매핑합니다. 샘플 `Book` 인스턴스를 저장하고, 해당 인스턴스를 검색하고, 해당 차원을 업데이트하고, 업데이트된 `Book`을 다시 저장합니다.



다음 예제를 테스트하기 위한 단계별 지침은 [.NET 코드 예시](CodeSamples.DotNet.md) 단원을 참조하세요.

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class HighLevelMappingArbitraryData
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                DynamoDBContext context = new DynamoDBContext(client);

                // 1. Create a book.
                DimensionType myBookDimensions = new DimensionType()
                {
                    Length = 8M,
                    Height = 11M,
                    Thickness = 0.5M
                };

                Book myBook = new Book
                {
                    Id = 501,
                    Title = "AWS SDK for .NET Object Persistence Model Handling Arbitrary Data",
                    ISBN = "999-9999999999",
                    BookAuthors = new List<string> { "Author 1", "Author 2" },
                    Dimensions = myBookDimensions
                };

                context.Save(myBook);

                // 2. Retrieve the book.
                Book bookRetrieved = context.Load<Book>(501);

                // 3. Update property (book dimensions).
                bookRetrieved.Dimensions.Height += 1;
                bookRetrieved.Dimensions.Length += 1;
                bookRetrieved.Dimensions.Thickness += 0.2M;
                // Update the book.
                context.Save(bookRetrieved);

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }
    }
    [DynamoDBTable("ProductCatalog")]
    public class Book
    {
        [DynamoDBHashKey] //Partition key
        public int Id
        {
            get; set;
        }
        [DynamoDBProperty]
        public string Title
        {
            get; set;
        }
        [DynamoDBProperty]
        public string ISBN
        {
            get; set;
        }
        // Multi-valued (set type) attribute.
        [DynamoDBProperty("Authors")]
        public List<string> BookAuthors
        {
            get; set;
        }
        // Arbitrary type, with a converter to map it to DynamoDB type.
        [DynamoDBProperty(typeof(DimensionTypeConverter))]
        public DimensionType Dimensions
        {
            get; set;
        }
    }

    public class DimensionType
    {
        public decimal Length
        {
            get; set;
        }
        public decimal Height
        {
            get; set;
        }
        public decimal Thickness
        {
            get; set;
        }
    }

    // Converts the complex type DimensionType to string and vice-versa.
    public class DimensionTypeConverter : IPropertyConverter
    {
        public DynamoDBEntry ToEntry(object value)
        {
            DimensionType bookDimensions = value as DimensionType;
            if (bookDimensions == null) throw new ArgumentOutOfRangeException();

            string data = string.Format("{1}{0}{2}{0}{3}", " x ",
                            bookDimensions.Length, bookDimensions.Height, bookDimensions.Thickness);

            DynamoDBEntry entry = new Primitive
            {
                Value = data
            };
            return entry;
        }

        public object FromEntry(DynamoDBEntry entry)
        {
            Primitive primitive = entry as Primitive;
            if (primitive == null || !(primitive.Value is String) || string.IsNullOrEmpty((string)primitive.Value))
                throw new ArgumentOutOfRangeException();

            string[] data = ((string)(primitive.Value)).Split(new string[] { " x " }, StringSplitOptions.None);
            if (data.Length != 3) throw new ArgumentOutOfRangeException();

            DimensionType complexData = new DimensionType
            {
                Length = Convert.ToDecimal(data[0]),
                Height = Convert.ToDecimal(data[1]),
                Thickness = Convert.ToDecimal(data[2])
            };
            return complexData;
        }
    }
}
```

# 이 개발자 안내서의 코드 예시 실행
<a name="CodeSamples"></a>

AWS SDK는 Amazon DynamoDB에 대한 광범위한 지원을 다음 언어로 제공합니다.
+ [Java](https://aws.amazon.com/sdk-for-java): 
+ [브라우저에서의 JavaScript](https://aws.amazon.com/sdk-for-browser)
+ [.NET](https://aws.amazon.com/sdk-for-net)
+ [Node.js](https://aws.amazon.com/sdk-for-node-js)
+ [PHP](https://aws.amazon.com/sdk-for-php)
+ [Python](https://aws.amazon.com/sdk-for-python)
+ [Ruby](https://aws.amazon.com/sdk-for-ruby)
+ [C\$1\$1](https://aws.amazon.com/sdk-for-cpp)
+ [Go](https://aws.amazon.com/sdk-for-go)
+ [Android](https://aws.amazon.com/mobile/sdk/): 
+ [iOS](https://aws.amazon.com/mobile/sdk/): 

이 개발자 안내서의 코드 예제에서는 다음의 프로그래밍 언어를 사용하여 DynamoDB 작업을 보다 깊이 있게 다룹니다.
+ [Java 코드 예](CodeSamples.Java.md)
+ [.NET 코드 예시](CodeSamples.DotNet.md)

이 연습을 시작하려면 먼저 AWS 계정을 생성하고, 액세스 키 및 보안 키를 얻고, 컴퓨터에서 AWS Command Line Interface(AWS CLI)를 설정해야 합니다. 자세한 내용은 [DynamoDB 설정(웹 서비스)](SettingUp.DynamoWebService.md) 섹션을 참조하세요.

**참고**  
DynamoDB 다운로드 가능 버전을 사용하는 경우, AWS CLI를 사용하여 테이블과 샘플 데이터를 생성해야 합니다. 또한 각 `--endpoint-url` 명령으로 AWS CLI 파라미터를 지정해야 합니다. 자세한 내용은 [로컬 엔드포인트 설정](DynamoDBLocal.UsageNotes.md#DynamoDBLocal.Endpoint) 섹션을 참조하세요.

# DynamoDB에서 테이블 생성 및 코드 예시에 대한 데이터 로드
<a name="SampleData"></a>

DynamoDB에서 테이블을 생성하고, 샘플 데이터 세트를 로드하고, 데이터를 쿼리하고, 데이터를 업데이트하는 방법에 대한 기본 사항은 아래를 참조하세요.
+ [1단계: DynamoDB에 테이블 생성](getting-started-step-1.md)
+ [2단계: DynamoDB 테이블에 데이터 쓰기](getting-started-step-2.md)
+ [3단계: DynamoDB 테이블의 데이터 읽기](getting-started-step-3.md)
+ [4단계: DynamoDB 테이블의 데이터 업데이트](getting-started-step-4.md)

# Java 코드 예
<a name="CodeSamples.Java"></a>

**Topics**
+ [Java: AWS 보안 인증 정보 설정](#CodeSamples.Java.Credentials)
+ [Java: AWS 리전 및 엔드포인트 설정](#CodeSamples.Java.RegionAndEndpoint)

이 개발자 안내서에는 Java 코드 조각과 실행 준비된 프로그램이 포함되어 있습니다. 다음 단원에서 이들 코드 예제를 찾을 수 있습니다.
+ [DynamoDB의 항목 및 속성 작업](WorkingWithItems.md)
+ [DynamoDB의 테이블 및 데이터 작업](WorkingWithTables.md)
+ [DynamoDB에서 테이블 쿼리](Query.md)
+ [DynamoDB에서 테이블 스캔](Scan.md)
+ [DynamoDB에서 보조 인덱스를 사용하여 데이터 액세스 개선](SecondaryIndexes.md)
+ [Java 1.x: DynamoDBMapper](DynamoDBMapper.md)
+ [DynamoDB Streams에 대한 변경 데이터 캡처](Streams.md)

Eclipse와 함께 [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/)를 사용하여 빠르게 시작할 수 있습니다. 완벽한 기능의 IDE 외에 자동 업데이트가 포함된 AWS SDK for Java와 사전 구성된 AWS 애플리케이션 개발 템플릿도 포함되어 있습니다.

**Java 코드 예제를 실행하려면(Eclipse 사용)**

1. [Eclipse](http://www.eclipse.org) IDE를 다운로드하고 설치합니다.

1. 를 다운로드하여 설치합니다..[AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/)

1. Eclipse를 시작하고 **Eclipse** 메뉴에서 **파일**, **새로 만들기**, **기타**를 차례대로 선택합니다.

1. **Select a wizard**에서 **AWS**, **AWS Java Project**, **Next**를 차례대로 선택합니다.

1. **Create an AWS Java**에서 다음을 수행합니다.

   1. **프로젝트 이름**에 프로젝트의 이름을 입력합니다.

   1. **Select Account**의 목록에서 자격 증명 프로필을 선택합니다.

      [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/)를 처음 사용하는 경우, **Configure AWS Accounts**(계정 구성)를 선택하여 AWS 보안 인증 정보를 설정합니다.

1. 프로젝트를 생성하려면 **Finish**를 선택합니다.

1. **Eclipse** 메뉴에서 **File**, **New**, **Class**를 차례대로 선택합니다.

1. **Java Class(Java 클래스)**에서 **이름**에 클래스 이름을 입력(실행하려는 코드 예제와 동일한 이름 사용)한 다음 **마침**을 선택하여 클래스를 생성합니다.

1. 설명서 페이지에서 코드 예제를 Eclipse 에디터로 복사합니다.

1. 코드를 실행하려면 Eclipse 메뉴에서 **실행**을 선택합니다.

SDK for Java는 DynamoDB 작업을 위한 스레드 세이프(thread-safe) 클라이언트를 제공합니다. 모범 사례로서 애플리케이션에서 클라이언트 하나를 생성한 후 스레드 간에 재사용해야 합니다.

자세한 내용은 [AWS SDK for Java](https://aws.amazon.com/sdk-for-java) 섹션을 참조하세요.

**참고**  
이 안내서의 코드 예제는 AWS SDK for Java의 최신 버전과 함께 사용해야 합니다.  
AWS Toolkit for Eclipse를 사용하는 경우 SDK for Java에 대해 자동 업데이트를 구성할 수 있습니다. Eclipse에서 이렇게 하려면 **기본 설정**으로 이동하고 **AWS Toolkit**, **AWS SDK for Java**, **Download new SDKs automatically(새 SDK를 자동으로 다운로드)**를 차례로 선택합니다.

## Java: AWS 보안 인증 정보 설정
<a name="CodeSamples.Java.Credentials"></a>

SDK for Java에서는 런타임에 애플리케이션에 AWS 자격 증명을 제공해야 합니다. 이 가이드의 코드 예시에서는 *AWS SDK for Java 개발자 안내서*의 [AWS 보안 인증 정보 설정](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/set-up-creds.html)에 설명된 대로 AWS 보안 인증 정보 파일을 사용한다고 가정합니다.

다음은 `~/.aws/credentials`라는 AWS 자격 증명 파일의 예입니다. 여기서 물결 문자(`~`)는 사용자의 홈 디렉터리입니다.

```
[default]
aws_access_key_id = AWS access key ID goes here
aws_secret_access_key = Secret key goes here
```

## Java: AWS 리전 및 엔드포인트 설정
<a name="CodeSamples.Java.RegionAndEndpoint"></a>

기본적으로 코드 예제는 미국 서부(오레곤) 리전에서 DynamoDB에 액세스합니다. `AmazonDynamoDB` 속성을 수정하여 리전을 변경할 수 있습니다.

다음 코드 예제에서는 새 `AmazonDynamoDB`를 인스턴스화합니다.

```
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import com.amazonaws.regions.Regions;
...
// This client will default to US West (Oregon)
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
.withRegion(Regions.US_WEST_2)
.build();
```

`withRegion` 메서드를 사용하면 사용할 수 있는 어떤 리전의 DynamoDB에 대해서도 코드를 실행할 수 있습니다. 전체 목록은 **Amazon Web Services 일반 참조에서 [AWS 리전 및 엔드포인트](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region)를 참조하세요.

컴퓨터에서 로컬로 DynamoDB를 사용하여 코드 예제를 실행하려면 다음과 같이 엔드포인트를 설정합니다.

### AWS SDK V1
<a name="CodeSamples.Java.RegionAndEndpoint.V1"></a>

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "us-west-2"))
.build();
```

### AWS SDK V2
<a name="CodeSamples.Java.RegionAndEndpoint.V2"></a>

```
DynamoDbClient client = DynamoDbClient.builder()
    .endpointOverride(URI.create("http://localhost:8000"))
    // The region is meaningless for local DynamoDb but required for client builder validation
    .region(Region.US_EAST_1)
    .credentialsProvider(StaticCredentialsProvider.create(
    AwsBasicCredentials.create("dummy-key", "dummy-secret")))
    .build();
```

# .NET 코드 예시
<a name="CodeSamples.DotNet"></a>

**Topics**
+ [.NET: AWS 보안 인증 정보 설정](#CodeSamples.DotNet.Credentials)
+ [.NET: AWS 리전 및 엔드포인트 설정](#CodeSamples.DotNet.RegionAndEndpoint)

이 안내서에는 .NET 코드 조각과 실행 준비된 프로그램이 포함되어 있습니다. 다음 단원에서 이들 코드 예제를 찾을 수 있습니다.
+ [DynamoDB의 항목 및 속성 작업](WorkingWithItems.md)
+ [DynamoDB의 테이블 및 데이터 작업](WorkingWithTables.md)
+ [DynamoDB에서 테이블 쿼리](Query.md)
+ [DynamoDB에서 테이블 스캔](Scan.md)
+ [DynamoDB에서 보조 인덱스를 사용하여 데이터 액세스 개선](SecondaryIndexes.md)
+ [DynamoDB에서 .NET 문서 모델을 사용하여 작업](DotNetSDKMidLevel.md)
+ [.NET 객체 지속성 모델 및 DynamoDB로 작업](DotNetSDKHighLevel.md)
+ [DynamoDB Streams에 대한 변경 데이터 캡처](Streams.md)

AWS SDK for .NET 및 Toolkit for Visual Studio를 함께 사용하면 빠르게 시작할 수 있습니다.

**.NET 코드 예제를 실행하려면((Visual Studio 사용)**

1. [Microsoft Visual Studio](https://www.visualstudio.com)를 다운로드하여 설치합니다.

1. (선택 사항) [Toolkit for Visual Studio](https://aws.amazon.com/visualstudio/)를 다운로드하여 설치합니다.

1. AWS 보안 인증을 설정합니다. 공유 AWS 자격 증명 파일(`~/.aws/credentials`)에서 자격 증명 프로파일을 구성합니다. 자세한 내용은 **AWS SDK for .NET 개발자 안내서의 [AWS 자격 증명 구성](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html)을 참조하세요.

1. Visual Studio를 시작합니다. **파일**, **새로 만들기**, **프로젝트**를 선택합니다.

1. **콘솔 앱**을 검색하고 .NET을 대상으로 하는 C\$1 템플릿을 선택한 후 **다음**을 선택합니다. 프로젝트 이름과 위치를 구성한 다음 **생성**을 선택합니다.

1. 프로젝트에 DynamoDB NuGet용 AWS SDK 패키지를 추가하려면 다음을 수행합니다.

   1. Solution Exploer에서 프로젝트의 컨텍스트 메뉴를 열고(마우스 오른쪽 버튼 클릭) **Manage NuGet Packages**를 선택합니다.

   1. NuGet Package Manager에서 **Browse**를 선택합니다.

   1. 검색 상자에 **AWSSDK.DynamoDBv2**를 입력하고 검색이 완료되기를 기다립니다.

   1. **AWSSDK.DynamoDBv2**를 선택한 다음 **설치**를 선택합니다.

1. Visual Studio 프로젝트에서 `Program.cs`를 엽니다. 내용을 실행하려는 설명서 페이지의 코드 예제로 바꿉니다.

1. 코드를 실행하려면 Visual Studio 도구 모음에서 **시작**을 선택합니다.

SDK for .NET은 DynamoDB 작업을 위한 스레드 세이프(thread-safe) 클라이언트를 제공합니다. 모범 사례로서 애플리케이션에서 클라이언트 하나를 생성한 후 스레드 간에 재사용해야 합니다.

자세한 내용은 [AWS SDK for .NET](https://aws.amazon.com/sdk-for-net)을 참조하세요.

**참고**  
이 안내서의 코드 예제는 AWS SDK for .NET의 최신 버전과 함께 사용해야 합니다.

## .NET: AWS 보안 인증 정보 설정
<a name="CodeSamples.DotNet.Credentials"></a>

SDK for .NET에서는 런타임에 애플리케이션에 AWS 자격 증명을 제공해야 합니다. 이 가이드의 코드 예시에서는 *AWS SDK for .NET 개발자 안내서*의 [SDK 스토어 사용](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#sdk-store)에 설명된 대로 SDK 스토어를 사용하여 AWS 보안 인증 정보 파일을 관리한다고 가정합니다.

Toolkit for Visual Studio는 계정 수에 제한 없이 다수의 자격 증명 집합을 지원합니다. 각 집합을 *프로필*이라고 부릅니다. Visual Studio는 애플리케이션이 런타임 도중에도 AWS 자격 증명을 찾을 수 있도록 프로젝트의 `App.config` 파일에 항목을 추가합니다.

다음 예제에서는 Toolkit for Visual Studio를 사용하여 새 프로젝트를 만들 때 생성되는 기본 `App.config` 파일을 보여줍니다.

```
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
    <add key="AWSProfileName" value="default"/>
    <add key="AWSRegion" value="us-west-2" />
 </appSettings>
</configuration>
```

런타임에 프로그램은 `AWSProfileName` 항목에 지정된 대로 `default` 자격 증명의 AWS 집합을 사용합니다. AWS 자격 증명 자체는 암호화된 형식으로 SDK 스토어에 보관됩니다. Toolkit for Visual Studio는 Visual Studio 안에서 자격 증명을 모두 관리할 수 있는 그래픽 사용자 인터페이스를 제공합니다. 자세한 내용은 *AWS Toolkit for Visual Studio 사용 설명서*에서 [보안 인증 정보 지정](https://docs.aws.amazon.com/AWSToolkitVS/latest/UserGuide/tkv_setup.html#creds)을 참조하세요.

**참고**  
기본적으로 코드 예제는 미국 서부(오레곤) 리전에서 DynamoDB에 액세스합니다. App.config 파일의 `AWSRegion` 항목을 수정하여 리전을 변경할 수 있습니다. `AWSRegion`은 DynamoDB를 사용할 수 있는 어느 리전으로도 설정할 수 있습니다. 전체 목록은 **Amazon Web Services 일반 참조에서 [AWS 리전 및 엔드포인트](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region)를 참조하세요.

## .NET: AWS 리전 및 엔드포인트 설정
<a name="CodeSamples.DotNet.RegionAndEndpoint"></a>

기본적으로 코드 예제는 미국 서부(오레곤) 리전에서 DynamoDB에 액세스합니다. `AWSRegion` 파일의 `App.config` 항목을 수정하여 리전을 변경할 수 있습니다. 또는 `AmazonDynamoDBClient` 속성을 수정하여 리전을 변경할 수 있습니다.

다음 코드 예제에서는 새 `AmazonDynamoDBClient`를 인스턴스화합니다. 클라이언트가 수정되어 코드가 다른 리전의 DynamoDB에 대해 실행됩니다.

```
AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig();
// This client will access the US East 1 region.
clientConfig.RegionEndpoint = RegionEndpoint.USEast1;
AmazonDynamoDBClient client = new AmazonDynamoDBClient(clientConfig);
```

전체 리전 목록은 **Amazon Web Services 일반 참조에서 [AWS 리전 및 엔드포인트](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region)를 참조하세요.

컴퓨터에서 로컬로 DynamoDB를 사용하여 코드 예제를 실행하려면 다음과 같이 엔드포인트를 설정합니다.

```
AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig();
// Set the endpoint URL
clientConfig.ServiceURL = "http://localhost:8000";
AmazonDynamoDBClient client = new AmazonDynamoDBClient(clientConfig);
```

# DynamoDB 하위 수준 API
<a name="Programming.LowLevelAPI"></a>

Amazon DynamoDB *하위 수준 API*는 DynamoDB의 프로토콜 수준 인터페이스입니다. 이 수준에서는 모든 HTTP(S) 요청이 올바른 형식이어야 하며, 유효한 디지털 서명이 있어야 합니다.

AWS SDK는 사용자를 대신하여 하위 수준 DynamoDB API 요청을 구성하고 DynamoDB의 응답을 처리합니다. 이로써 하위 수준 세부 사항 대신 애플리케이션 로직에 집중할 수 있습니다. 그러나 하위 수준 DynamoDB API의 작동 방식에 대한 기본적 이해는 여전히 도움이 될 수 있습니다.

하위 수준 DynamoDB API에 대한 자세한 내용은 [Amazon DynamoDB API 참조](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)를 참조하세요.

**참고**  
DynamoDB Streams의 자체 하위 수준 API는 DynamoDB의 그것과 별개이며, AWS SDK가 완벽하게 지원합니다.  
자세한 내용은 [DynamoDB Streams에 대한 변경 데이터 캡처](Streams.md) 섹션을 참조하세요. 하위 수준 DynamoDB Streams API는 [Amazon DynamoDB Streams API 참조](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Operations_Amazon_DynamoDB_Streams.html)를 참조하세요.

하위 수준 DynamoDB API는 JavaScript Object Notation(JSON)을 연결 프로토콜 형식으로 사용합니다. JSON은 데이터를 계층 구조로 나타내므로 데이터 값과 데이터 구조 모두 동시에 전달됩니다. 이름-값 페어는 `name:value` 형식으로 정의됩니다. 데이터 계층은 이름-값 페어의 중첩된 대괄호로 정의됩니다.

DynamoDB는 JSON을 오직 전송 프로토콜로 사용하며 스토리지 형식으로는 사용하지 않습니다. AWS SDK는 JSON을 사용하여 DynamoDB에 데이터를 보내고 DynamoDB는 JSON으로 응답합니다. DynamoDB는 데이터를 JSON 형식으로 지속적으로 저장하지 않습니다.

**참고**  
JSON에 대한 자세한 내용은 `JSON.org` 웹사이트에서 [JSON 소개](http://json.org)를 참조하세요.

**Topics**
+ [요청 형식](#Programming.LowLevelAPI.RequestFormat)
+ [응답 형식](#Programming.LowLevelAPI.ResponseFormat)
+ [데이터 형식 서술자](#Programming.LowLevelAPI.DataTypeDescriptors)
+ [숫자 데이터](#Programming.LowLevelAPI.Numbers)
+ [이진 데이터](#Programming.LowLevelAPI.Binary)

![\[DynamoDB 하위 수준 API 및 AWS SDK가 프로토콜 수준 요청 및 응답을 처리하는 방법입니다.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/SDKSupport.DDBLowLevelAPI.png)


## 요청 형식
<a name="Programming.LowLevelAPI.RequestFormat"></a>

DynamoDB 하위 수준 API는 HTTP(S) `POST` 요청을 입력으로 받아들입니다. AWS SDK는 이 요청을 구성합니다.

`Pets`(파티션 키) 및 `AnimalType`(정렬 키)으로 구성된 키 스키마가 포함된 `Name`이라는 이름의 테이블이 있는 경우 이 두 가지 속성 모두 `string` 유형입니다. `Pets`에서 항목을 검색하기 위해 AWS SDK는 다음 요청을 구성합니다.

```
POST / HTTP/1.1
Host: dynamodb.<region>.<domain>;
Accept-Encoding: identity
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.0
Authorization: AWS4-HMAC-SHA256 Credential=<Credential>, SignedHeaders=<Headers>, Signature=<Signature>
X-Amz-Date: <Date> 
X-Amz-Target: DynamoDB_20120810.GetItem

{
    "TableName": "Pets",
    "Key": {
        "AnimalType": {"S": "Dog"},
        "Name": {"S": "Fido"}
    }
}
```

이 요청에 대해 다음을 참조하세요.
+ `Authorization` 헤더에는 DynamoDB가 요청을 인증하는 데 필요한 정보가 포함되어 있습니다. 자세한 내용은 **Amazon Web Services 일반 참조의 [AWS API 요청에 서명](https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html) 및 [서명 버전 4 서명 프로세스](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)를 참조하세요.
+ `X-Amz-Target` 헤더에는 DynamoDB 작업의 이름인 `GetItem`이 포함되어 있습니다. (여기에 하위 API 버전(이 경우에는 `20120810`)도 포함됩니다.)
+ 요청의 페이로드(본문)에는 JSON 형식의 작업을 위한 파라미터가 포함되어 있습니다. `GetItem` 작업의 경우, 파라미터는 `TableName` 및 `Key`입니다.

## 응답 형식
<a name="Programming.LowLevelAPI.ResponseFormat"></a>

DynamoDB는 요청을 수신하면 이를 처리하고 응답을 반환합니다. 이전에 나온 요청의 경우 다음 예제와 같이 HTTP(S) 응답 페이로드에 해당 작업 결과가 포함됩니다.

```
HTTP/1.1 200 OK
x-amzn-RequestId: <RequestId>
x-amz-crc32: <Checksum>
Content-Type: application/x-amz-json-1.0
Content-Length: <PayloadSizeBytes>
Date: <Date>
{
    "Item": {
        "Age": {"N": "8"},
        "Colors": {
            "L": [
                {"S": "White"},
                {"S": "Brown"},
                {"S": "Black"}
            ]
        },
        "Name": {"S": "Fido"},
        "Vaccinations": {
            "M": {
                "Rabies": {
                    "L": [
                        {"S": "2009-03-17"},
                        {"S": "2011-09-21"},
                        {"S": "2014-07-08"}
                    ]
                },
                "Distemper": {"S": "2015-10-13"}
            }
        },
        "Breed": {"S": "Beagle"},
        "AnimalType": {"S": "Dog"}
    }
}
```

이때 AWS SDK는 추가 처리를 위해 애플리케이션에 응답 데이터를 반환합니다.

**참고**  
DynamoDB가 요청을 처리할 수 없는 경우 HTTP 오류 코드 및 메시지를 반환합니다. AWS SDK는 이를 예외 형식으로 애플리케이션에 전파합니다. 자세한 내용은 [DynamoDB 관련 오류 처리](Programming.Errors.md) 섹션을 참조하세요.

## 데이터 형식 서술자
<a name="Programming.LowLevelAPI.DataTypeDescriptors"></a>

하위 수준 DynamoDB API 프로토콜에서는 각 속성에 데이터 형식 서술자가 포함되어야 합니다. *데이터 형식 서술자*는 DynamoDB에 각 속성을 해석하는 방법을 알려 주는 토큰입니다.

[요청 형식](#Programming.LowLevelAPI.RequestFormat) 및 [응답 형식](#Programming.LowLevelAPI.ResponseFormat)의 예는 데이터 형식 서술자가 어떻게 사용되는지 보여 줍니다. `GetItem` 요청은 `S` 키 스키마 속성(`Pets` 및 `AnimalType`)에 대해 `Name`를 지정하며, 이는 `string` 유형입니다. `GetItem` 응답에는 `string`(`S`), `number`(`N`), `map`(`M`) 및 `list`(`L`) 형식의 *Pets* 항목이 포함됩니다.

다음은 DynamoDB 데이터 형식 서술자의 전체 목록입니다.
+ **`S`** - 문자열
+ **`N`** - 숫자
+ **`B`** - 이진수
+ **`BOOL`** - 부울
+ **`NULL`** - Null
+ **`M`** - 맵
+ **`L`** - 목록
+ **`SS`** - 문자열 집합
+ **`NS`** - 숫자 집합
+ **`BS`** - 이진수 집합

다음 표에는 각 데이터 유형 설명자의 올바른 JSON 형식이 나와 있습니다. 숫자는 정밀도를 유지하기 위해 문자열로 표시되는 반면, 부울과 null은 기본 JSON 유형을 사용합니다.


| 설명자 | JSON 형식 | 참고 | 
| --- | --- | --- | 
| S | \$1"S": "Hello"\$1 | 값은 JSON 문자열입니다. | 
| N | \$1"N": "123.45"\$1 | 값은 JSON 번호가 아닌 문자열입니다. 이렇게 하면 언어 간 정밀도가 유지됩니다. | 
| B | \$1"B": "dGhpcyBpcyBhIHRlc3Q="\$1 | 값은 base64로 인코딩된 문자열입니다. | 
| BOOL | \$1"BOOL": true\$1 | 값은 문자열이 아닌 JSON 부울(true 또는 false)입니다. | 
| NULL | \$1"NULL": true\$1 | 값은 null을 나타내는 JSON 부울 true입니다. | 
| M | \$1"M": \$1"Name": \$1"S": "Joe"\$1\$1\$1 | 값은 속성 이름-값 페어의 JSON 객체입니다. | 
| L | \$1"L": [\$1"S": "Red"\$1, \$1"N": "5"\$1]\$1 | 값은 속성 값의 JSON 배열입니다. | 
| SS | \$1"SS": ["Red", "Blue"]\$1 | 값은 문자열의 JSON 배열입니다. | 
| NS | \$1"NS": ["1", "2.5"]\$1 | 값은 숫자 문자열의 JSON 배열입니다. | 
| BS | \$1"BS": ["U3Vubnk=", "UmFpbnk="]\$1 | 값은 base64로 인코딩된 문자열의 JSON 배열입니다. | 

**참고**  
 DynamoDB 데이터 형식에 대한 자세한 내용은 [데이터 타입](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes) 단원을 참조하세요.

## 숫자 데이터
<a name="Programming.LowLevelAPI.Numbers"></a>

프로그래밍 언어마다 JSON 지원 수준이 다릅니다. 경우에 따라서는 JSON 문서를 확인하고 구문 분석하는 데 타사 라이브러리를 사용해야 할 수도 있습니다.

일부 타사 라이브러리는 JSON 숫자 형식을 기초로 `int`, `long` 또는 `double` 같은 자체 형식을 제공합니다. 그러나 DynamoDB의 기본 숫자 데이터 형식은 이러한 다른 데이터 형식에 정확히 매핑되지 않으므로 이러한 형식 구분은 충돌을 야기할 수 있습니다. 뿐만 아니라 많은 JSON 라이브러리는 고정 전체 자릿수 숫자 값을 처리하지 않으며, 소수점을 포함하는 숫자열의 double 데이터 형식을 자동으로 유추합니다.

DynamoDB는 이러한 문제를 해결하기 위해 데이터 손실이 없는 단일 숫자 형식을 제공합니다. 또한 사용자의 동의 없이 double 값으로 암시적으로 변환되는 것을 방지하기 위해 DynamoDB는 숫자 값의 데이터 전송에 문자열을 사용합니다. 이러한 접근 방식은 속성 값을 업데이트하는 데 유연성을 제공하는 동시에 "1", "2", "3"을 적절한 순서로 입력하는 등 적절한 정렬 의미 체계를 유지합니다.

애플리케이션에 숫자 전체 자릿수가 중요한 경우, DynamoDB로 전달하기 전에 숫자 값을 문자열로 변환해야 합니다.

## 이진 데이터
<a name="Programming.LowLevelAPI.Binary"></a>

DynamoDB는 이진 속성을 지원합니다. 그러나 JSON은 이진 데이터 인코딩은 기본적으로 지원하지 않습니다. 요청에서 이진 데이터를 보내려면 Base64 형식으로 인코딩해야 합니다. DynamoDB는 요청을 받아 Base64를 다시 이진수로 디코딩합니다.

DynamoDB에서 사용되는 base64 인코딩 체계는 IETF(Internet Engineering Task Force) 웹 사이트의 [RFC 4648](http://tools.ietf.org/html/rfc4648)에 설명되어 있습니다.