

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Pelajari dasar-dasar DynamoDB Enhanced Client API
<a name="ddb-en-client-use"></a>

[Topik ini membahas fitur dasar DynamoDB Enhanced Client API dan membandingkannya dengan API klien DynamoDB standar.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html)

Jika Anda baru mengenal DynamoDB Enhanced Client API, kami sarankan Anda melalui tutorial [pengantar](ddb-en-client-getting-started.md) untuk membiasakan diri dengan kelas fundamental.

## item DynamoDB di Java
<a name="ddb-en-client-use-usecase"></a>

Tabel DynamoDB menyimpan item. Bergantung pada kasus penggunaan Anda, item di sisi Java dapat berbentuk data atau struktur terstruktur statis yang dibuat secara dinamis. 

Jika kasus penggunaan Anda memanggil item dengan kumpulan atribut yang konsisten, gunakan [kelas beranotasi](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean) atau gunakan [pembuat](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder) untuk menghasilkan tipe statis yang sesuai. `TableSchema` 

Atau, jika Anda perlu menyimpan item yang terdiri dari berbagai struktur, buat`DocumentTableSchema`. `DocumentTableSchema`adalah bagian dari [Enhanced Document API](ddb-en-client-doc-api.md) dan hanya memerlukan kunci primer yang diketik secara statis dan bekerja dengan `EnhancedDocument` instance untuk menyimpan elemen data. Enhanced Document API dibahas dalam [topik lain.](ddb-en-client-doc-api.md)

## Tipe atribut untuk kelas model data
<a name="ddb-en-client-use-types"></a>

Meskipun DynamoDB [mendukung sejumlah kecil tipe atribut](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) dibandingkan dengan sistem tipe kaya Java, DynamoDB Enhanced Client API menyediakan mekanisme untuk mengonversi anggota kelas Java ke dan dari tipe atribut DynamoDB.

Jenis atribut (properti) kelas data Java Anda harus berupa tipe objek, bukan primitif. Misalnya, selalu gunakan `Long` dan `Integer` objek tipe data, bukan `long` dan `int` primitif.

[Secara default, DynamoDB Enhanced Client API mendukung konverter atribut untuk sejumlah besar tipe, [seperti](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) Integer, String[,](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) dan Instant. [BigDecimal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/BigDecimalAttributeConverter.html)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/InstantAsStringAttributeConverter.html) Daftar ini muncul di [kelas implementasi AttributeConverter antarmuka yang dikenal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html). Daftar ini mencakup banyak jenis dan koleksi seperti peta, daftar, dan set.

Untuk menyimpan data untuk jenis atribut yang tidak didukung secara default atau tidak sesuai dengan JavaBean konvensi, Anda dapat menulis `AttributeConverter` implementasi khusus untuk melakukan konversi. Lihat bagian konversi atribut untuk [contoh](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example).

Untuk menyimpan data untuk tipe atribut yang kelasnya sesuai dengan spesifikasi kacang Java (atau [kelas data yang tidak dapat diubah](ddb-en-client-use-immut.md)), Anda dapat mengambil dua pendekatan. 
+ Jika Anda memiliki akses ke file sumber, Anda dapat membuat anotasi kelas dengan `@DynamoDbBean` (atau`@DynamoDbImmutable`). Bagian yang membahas atribut bersarang menunjukkan [contoh](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-anno) penggunaan kelas beranotasi.
+ Jika tidak memiliki akses ke file sumber dari kelas JavaBean data untuk atribut (atau Anda tidak ingin membubuhi keterangan file sumber kelas yang Anda memiliki akses ke), maka Anda dapat menggunakan pendekatan builder. Ini menciptakan skema tabel tanpa mendefinisikan kunci. Kemudian, Anda dapat menyusun skema tabel ini di dalam skema tabel lain untuk melakukan pemetaan. Bagian atribut bersarang memiliki [contoh](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-builder) yang menunjukkan penggunaan skema bersarang.

### Nilai nol
<a name="ddb-en-client-use-types-nulls"></a>

Saat Anda menggunakan `putItem` metode ini, klien yang disempurnakan tidak menyertakan atribut bernilai nol dari objek data yang dipetakan dalam permintaan ke DynamoDB.

Perilaku default SDK untuk `updateItem` permintaan menghapus atribut dari item di DynamoDB yang disetel ke null dalam objek yang Anda kirimkan dalam metode. `updateItem` Jika Anda bermaksud memperbarui beberapa nilai atribut dan menjaga yang lain tidak berubah, Anda memiliki dua opsi.
+ Ambil item (dengan menggunakan`getItem`) sebelum Anda membuat perubahan pada nilai. Dengan menggunakan pendekatan ini, SDK mengirimkan semua nilai yang diperbarui dan lama ke DynamoDB.
+ Gunakan salah satu `[IgnoreNullsMode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html).SCALAR_ONLY` atau `IgnoreNullsMode.MAPS_ONLY` ketika Anda membuat permintaan untuk memperbarui item. Kedua mode mengabaikan properti bernilai nol dalam objek yang mewakili atribut skalar di DynamoDB. [Perbarui item yang berisi tipe kompleks](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-updates)Topik dalam panduan ini berisi informasi lebih lanjut tentang `IgnoreNullsMode` nilai-nilai dan cara bekerja dengan tipe yang kompleks.

Contoh berikut menunjukkan `ignoreNullsMode()` untuk `updateItem()` metode ini.

```
    public static void updateItemNullsExample() {
        Customer customer = new Customer();
        customer.setCustName("CustomerName");
        customer.setEmail("email");
        customer.setId("1");
        customer.setRegistrationDate(Instant.now());

        logger.info("Original customer: {}", customer);

        // Put item with values for all attributes.
        try {
            customerAsyncDynamoDbTable.putItem(customer).join();
        } catch (RuntimeException rte) {
            logger.error("A exception occurred during putItem: {}", rte.getCause().getMessage(), rte);
            return;
        }

        // Create a Customer instance with the same 'id' and 'email' values, but a different 'name' value.
        // Do not set the 'registrationDate' attribute.
        Customer customerForUpdate = new Customer();
        customerForUpdate.setCustName("NewName");
        customerForUpdate.setEmail("email");
        customerForUpdate.setId("1");

        // Update item without setting the 'registrationDate' property and set IgnoreNullsMode to SCALAR_ONLY.
        try {
            Customer updatedWithNullsIgnored = customerAsyncDynamoDbTable.updateItem(b -> b
                            .item(customerForUpdate)
                            .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY))
                    .join();
            logger.info("Customer updated with nulls ignored: {}", updatedWithNullsIgnored.toString());
        } catch (RuntimeException rte) {
            logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte);
            return;
        }

        // Update item without setting the registrationDate attribute and not setting ignoreNulls to true.
        try {
            Customer updatedWithNullsUsed = customerAsyncDynamoDbTable.updateItem(customerForUpdate)
                    .join();
            logger.info("Customer updated with nulls used: {}", updatedWithNullsUsed.toString());
        } catch (RuntimeException rte) {
            logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte);
        }
    }


// Logged lines. 
Original customer: Customer [id=1, name=CustomerName, email=email, regDate=2024-10-11T14:12:30.222858Z]
Customer updated with nulls ignored: Customer [id=1, name=NewName, email=email, regDate=2024-10-11T14:12:30.222858Z]
Customer updated with nulls used: Customer [id=1, name=NewName, email=email, regDate=null]
```

## Metode dasar DynamoDB Enhanced Client
<a name="ddb-en-client-use-basic-ops"></a>

Metode dasar peta klien yang disempurnakan ke operasi layanan DynamoDB yang dinamai menurut namanya. Contoh berikut menunjukkan variasi paling sederhana dari setiap metode. Anda dapat menyesuaikan setiap metode dengan meneruskan objek permintaan yang disempurnakan. Objek permintaan yang disempurnakan menawarkan sebagian besar fitur yang tersedia di klien DynamoDB standar. Mereka sepenuhnya didokumentasikan dalam Referensi AWS SDK for Java 2.x API.

Contoh menggunakan yang [`Customer` kelas](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) ditunjukkan sebelumnya.

```
// CreateTable
customerTable.createTable();

// GetItem
Customer customer = customerTable.getItem(Key.builder().partitionValue("a123").build());

// UpdateItem
Customer updatedCustomer = customerTable.updateItem(customer);

// PutItem
customerTable.putItem(customer);

// DeleteItem
Customer deletedCustomer = customerTable.deleteItem(Key.builder().partitionValue("a123").sortValue(456).build());

// Query
PageIterable<Customer> customers = customerTable.query(keyEqualTo(k -> k.partitionValue("a123")));

// Scan
PageIterable<Customer> customers = customerTable.scan();

// BatchGetItem
BatchGetResultPageIterable batchResults = 
    enhancedClient.batchGetItem(r -> r.addReadBatch(ReadBatch.builder(Customer.class)
                                      .mappedTableResource(customerTable)
                                      .addGetItem(key1)
                                      .addGetItem(key2)
                                      .addGetItem(key3)
                                      .build()));

// BatchWriteItem
batchResults = enhancedClient.batchWriteItem(r -> r.addWriteBatch(WriteBatch.builder(Customer.class)
                                                   .mappedTableResource(customerTable)
                                                   .addPutItem(customer)
                                                   .addDeleteItem(key1)
                                                   .addDeleteItem(key1)
                                                   .build()));

// TransactGetItems
transactResults = enhancedClient.transactGetItems(r -> r.addGetItem(customerTable, key1)
                                                        .addGetItem(customerTable, key2));

// TransactWriteItems
enhancedClient.transactWriteItems(r -> r.addConditionCheck(customerTable, 
                                                           i -> i.key(orderKey)
                                                                 .conditionExpression(conditionExpression))
                                        .addUpdateItem(customerTable, customer)
                                        .addDeleteItem(customerTable, key));
```

## Bandingkan DynamoDB Enhanced Client dengan klien DynamoDB standar
<a name="ddb-en-client-use-compare"></a>

Baik APIs klien DynamoDB [- standar [dan](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) ditingkatkan -](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html) memungkinkan Anda bekerja dengan tabel DynamoDB untuk melakukan operasi tingkat data CRUD (membuat, membaca, memperbarui, dan menghapus). Perbedaan antara klien APIs adalah bagaimana hal itu dicapai. Menggunakan klien standar, Anda bekerja secara langsung dengan atribut data tingkat rendah. API klien yang disempurnakan menggunakan kelas Java yang sudah dikenal dan memetakan ke API tingkat rendah di belakang layar.

Sementara kedua klien APIs mendukung operasi tingkat data, klien DynamoDB standar juga mendukung operasi tingkat sumber daya. Operasi tingkat sumber daya mengelola database, seperti membuat cadangan, daftar tabel, dan memperbarui tabel. API klien yang disempurnakan mendukung sejumlah operasi tingkat sumber daya tertentu seperti membuat, mendeskripsikan, dan menghapus tabel.

Untuk mengilustrasikan pendekatan berbeda yang digunakan oleh dua klien APIs, contoh kode berikut menunjukkan pembuatan `ProductCatalog` tabel yang sama menggunakan klien standar dan klien yang disempurnakan.

### Bandingkan: Buat tabel menggunakan klien DynamoDB standar
<a name="ddb-en-client-use-compare-cs1"></a>

```
DependencyFactory.dynamoDbClient().createTable(builder -> builder
        .tableName(TABLE_NAME)
        .attributeDefinitions(
                b -> b.attributeName("id").attributeType(ScalarAttributeType.N),
                b -> b.attributeName("title").attributeType(ScalarAttributeType.S),
                b -> b.attributeName("isbn").attributeType(ScalarAttributeType.S)
        )
        .keySchema(
                builder1 -> builder1.attributeName("id").keyType(KeyType.HASH),
                builder2 -> builder2.attributeName("title").keyType(KeyType.RANGE)
        )
        .globalSecondaryIndexes(builder3 -> builder3
                        .indexName("products_by_isbn")
                        .keySchema(builder2 -> builder2
                                .attributeName("isbn").keyType(KeyType.HASH))
                        .projection(builder2 -> builder2
                                .projectionType(ProjectionType.INCLUDE)
                                .nonKeyAttributes("price", "authors"))
                        .provisionedThroughput(builder4 -> builder4
                                .writeCapacityUnits(5L).readCapacityUnits(5L))
        )
        .provisionedThroughput(builder1 -> builder1
                .readCapacityUnits(5L).writeCapacityUnits(5L))
);
```

### Bandingkan: Buat tabel menggunakan DynamoDB Enhanced Client
<a name="ddb-en-client-use-compare-cs2"></a>

```
DynamoDbEnhancedClient enhancedClient = DependencyFactory.enhancedClient();
productCatalog = enhancedClient.table(TABLE_NAME, TableSchema.fromImmutableClass(ProductCatalog.class));
productCatalog.createTable(b -> b
        .provisionedThroughput(b1 -> b1.readCapacityUnits(5L).writeCapacityUnits(5L))
        .globalSecondaryIndices(b2 -> b2.indexName("products_by_isbn")
                .projection(b4 -> b4
                        .projectionType(ProjectionType.INCLUDE)
                        .nonKeyAttributes("price", "authors"))
                .provisionedThroughput(b3 -> b3.writeCapacityUnits(5L).readCapacityUnits(5L))
        )
);
```

Klien yang disempurnakan menggunakan kelas data beranotasi berikut. DynamoDB Enhanced Client memetakan tipe data Java ke tipe data DynamoDB untuk kode verbose yang lebih sedikit yang lebih mudah diikuti. `ProductCatalog`adalah contoh menggunakan kelas yang tidak dapat diubah dengan DynamoDB Enhanced Client. Penggunaan kelas Immutable untuk kelas data yang dipetakan [dibahas nanti dalam topik](ddb-en-client-use-immut.md) ini.

### `ProductCatalog` kelas
<a name="ddb-en-client-use-compare-cs3"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbIgnore;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.math.BigDecimal;
import java.util.Objects;
import java.util.Set;

@DynamoDbImmutable(builder = ProductCatalog.Builder.class)
public class ProductCatalog implements Comparable<ProductCatalog> {
    private Integer id;
    private String title;
    private String isbn;
    private Set<String> authors;
    private BigDecimal price;


    private ProductCatalog(Builder builder){
        this.authors = builder.authors;
        this.id = builder.id;
        this.isbn = builder.isbn;
        this.price = builder.price;
        this.title = builder.title;
    }

    public static Builder builder(){ return new Builder(); }

    @DynamoDbPartitionKey
    public Integer id() { return id; }
    
    @DynamoDbSortKey
    public String title() { return title; }
    
    @DynamoDbSecondaryPartitionKey(indexNames = "products_by_isbn")
    public String isbn() { return isbn; }
    public Set<String> authors() { return authors; }
    public BigDecimal price() { return price; }


    public static final class Builder {
      private Integer id;
      private String title;
      private String isbn;
      private Set<String> authors;
      private BigDecimal price;
      private Builder(){}

      public Builder id(Integer id) { this.id = id; return this; }
      public Builder title(String title) { this.title = title; return this; }
      public Builder isbn(String ISBN) { this.isbn = ISBN; return this; }
      public Builder authors(Set<String> authors) { this.authors = authors; return this; }
      public Builder price(BigDecimal price) { this.price = price; return this; }
      public ProductCatalog build() { return new ProductCatalog(this); }
  }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("ProductCatalog{");
        sb.append("id=").append(id);
        sb.append(", title='").append(title).append('\'');
        sb.append(", isbn='").append(isbn).append('\'');
        sb.append(", authors=").append(authors);
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProductCatalog that = (ProductCatalog) o;
        return id.equals(that.id) && title.equals(that.title) && Objects.equals(isbn, that.isbn) && Objects.equals(authors, that.authors) && Objects.equals(price, that.price);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, title, isbn, authors, price);
    }

    @Override
    @DynamoDbIgnore
    public int compareTo(ProductCatalog other) {
        if (this.id.compareTo(other.id) != 0){
            return this.id.compareTo(other.id);
        } else {
            return this.title.compareTo(other.title);
        }
    }
}
```

Dua contoh kode berikut dari penulisan batch menggambarkan verboseness dan kurangnya keamanan tipe saat menggunakan klien standar sebagai lawan dari klien yang ditingkatkan.

### Bandingkan: Batch write menggunakan klien DynamoDB standar
<a name="ddb-en-client-use-compare-cs4"></a>

```
    public static void batchWriteStandard(DynamoDbClient dynamoDbClient, String tableName) {

        Map<String, AttributeValue> catalogItem = Map.of(
                "authors", AttributeValue.builder().ss("a", "b").build(),
                "id", AttributeValue.builder().n("1").build(),
                "isbn", AttributeValue.builder().s("1-565-85698").build(),
                "title", AttributeValue.builder().s("Title 1").build(),
                "price", AttributeValue.builder().n("52.13").build());

        Map<String, AttributeValue> catalogItem2 = Map.of(
                "authors", AttributeValue.builder().ss("a", "b", "c").build(),
                "id", AttributeValue.builder().n("2").build(),
                "isbn", AttributeValue.builder().s("1-208-98073").build(),
                "title", AttributeValue.builder().s("Title 2").build(),
                "price", AttributeValue.builder().n("21.99").build());

        Map<String, AttributeValue> catalogItem3 = Map.of(
                "authors", AttributeValue.builder().ss("g", "k", "c").build(),
                "id", AttributeValue.builder().n("3").build(),
                "isbn", AttributeValue.builder().s("7-236-98618").build(),
                "title", AttributeValue.builder().s("Title 3").build(),
                "price", AttributeValue.builder().n("42.00").build());

        Set<WriteRequest> writeRequests = Set.of(
                WriteRequest.builder().putRequest(b -> b.item(catalogItem)).build(),
                WriteRequest.builder().putRequest(b -> b.item(catalogItem2)).build(),
                WriteRequest.builder().putRequest(b -> b.item(catalogItem3)).build());

        Map<String, Set<WriteRequest>> productCatalogItems = Map.of(
                "ProductCatalog", writeRequests);

        BatchWriteItemResponse response = dynamoDbClient.batchWriteItem(b -> b.requestItems(productCatalogItems));

        logger.info("Unprocessed items: " + response.unprocessedItems().size());
    }
```

### Bandingkan: Batch write menggunakan DynamoDB Enhanced Client
<a name="ddb-en-client-use-compare-cs5"></a>

```
    public static void batchWriteEnhanced(DynamoDbTable<ProductCatalog> productCatalog) {
        ProductCatalog prod = ProductCatalog.builder()
                .id(1)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(52.13))
                .title("Title 1")
                .build();
        ProductCatalog prod2 = ProductCatalog.builder()
                .id(2)
                .isbn("1-208-98073")
                .authors(new HashSet<>(Arrays.asList("a", "b", "c")))
                .price(BigDecimal.valueOf(21.99))
                .title("Title 2")
                .build();
        ProductCatalog prod3 = ProductCatalog.builder()
                .id(3)
                .isbn("7-236-98618")
                .authors(new HashSet<>(Arrays.asList("g", "k", "c")))
                .price(BigDecimal.valueOf(42.00))
                .title("Title 3")
                .build();

        BatchWriteResult batchWriteResult = DependencyFactory.enhancedClient()
                .batchWriteItem(b -> b.writeBatches(
                        WriteBatch.builder(ProductCatalog.class)
                                .mappedTableResource(productCatalog)
                                .addPutItem(prod).addPutItem(prod2).addPutItem(prod3)
                                .build()
                ));
        logger.info("Unprocessed items: " + batchWriteResult.unprocessedPutItemsForTable(productCatalog).size());
    }
```

# Bekerja dengan kelas data yang tidak dapat diubah
<a name="ddb-en-client-use-immut"></a>

Fitur pemetaan DynamoDB Enhanced Client API bekerja dengan kelas data yang tidak dapat diubah. Kelas yang tidak dapat diubah hanya memiliki getter dan memerlukan kelas pembangun yang digunakan SDK untuk membuat instance kelas. Alih-alih menggunakan `@DynamoDbBean` anotasi seperti yang ditunjukkan di [kelas Pelanggan, kelas](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) yang tidak dapat diubah menggunakan `@DynamoDbImmutable` anotasi, yang mengambil parameter yang menunjukkan kelas pembuat untuk digunakan.

Kelas berikut adalah versi yang tidak dapat diubah dari. `Customer`

```
package org.example.tests.model.immutable;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.time.Instant;

@DynamoDbImmutable(builder = CustomerImmutable.Builder.class)
public class CustomerImmutable {
    private final String id;
    private final String name;
    private final String email;
    private final Instant regDate;

    private CustomerImmutable(Builder b) {
        this.id = b.id;
        this.email = b.email;
        this.name = b.name;
        this.regDate = b.regDate;
    }

    // This method will be automatically discovered and used by the TableSchema.
    public static Builder builder() { return new Builder(); }

    @DynamoDbPartitionKey
    public String id() { return this.id; }

    @DynamoDbSortKey
    public String email() { return this.email; }

    @DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name")
    public String name() { return this.name; }

    @DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"})
    public Instant regDate() { return this.regDate; }

    public static final class Builder {
        private String id;
        private String email;
        private String name;
        private Instant regDate;

        // The private Builder constructor is visible to the enclosing CustomerImmutable class.
        private Builder() {}

        public Builder id(String id) { this.id = id; return this; }
        public Builder email(String email) { this.email = email; return this; }
        public Builder name(String name) { this.name = name; return this; }
        public Builder regDate(Instant regDate) { this.regDate = regDate; return this; }

        // This method will be automatically discovered and used by the TableSchema.
        public CustomerImmutable build() { return new CustomerImmutable(this); }
    }
}
```

Anda harus memenuhi persyaratan berikut ketika Anda membuat anotasi kelas data dengan. `@DynamoDbImmutable`

1. Setiap metode yang keduanya bukan penggantian `Object.class` dan belum dianotasi `@DynamoDbIgnore` harus menjadi pengambil untuk atribut tabel DynamoDB.

1. Setiap pengambil harus memiliki penyetel case-sensitive yang sesuai pada kelas builder.

1. Hanya satu dari kondisi konstruksi berikut yang harus dipenuhi.
   + Kelas builder harus memiliki konstruktor default publik.
   + Kelas data harus memiliki metode statis publik bernama `builder()` yang tidak mengambil parameter dan mengembalikan instance dari kelas builder. Opsi ini ditampilkan di kelas yang tidak dapat diubah`Customer`.

1.  Kelas builder harus memiliki metode publik bernama `build()` yang tidak mengambil parameter dan mengembalikan instance dari kelas yang tidak dapat diubah. 

Untuk membuat `TableSchema` untuk kelas abadi Anda, gunakan `fromImmutableClass()` metode pada `TableSchema` seperti yang ditunjukkan dalam cuplikan berikut.

```
static final TableSchema<CustomerImmutable> customerImmutableTableSchema = 
                         TableSchema.fromImmutableClass(CustomerImmutable.class);
```

Sama seperti Anda dapat membuat tabel DynamoDB dari kelas yang bisa berubah, Anda dapat membuatnya dari kelas yang tidak dapat diubah dengan panggilan satu kali ke dari seperti *yang ditunjukkan dalam* contoh `createTable()` cuplikan berikut`DynamoDbTable`.

```
static void createTableFromImmutable(DynamoDbEnhancedClient enhancedClient, String tableName, DynamoDbWaiter waiter){
    // First, create an in-memory representation of the table using the 'table()' method of the DynamoDb Enhanced Client.
    // 'table()' accepts a name for the table and a TableSchema instance that you created previously.
    DynamoDbTable<CustomerImmutable> customerDynamoDbTable = enhancedClient
            .table(tableName, TableSchema.fromImmutableClass(CustomerImmutable.class));
        
    // Second, call the 'createTable()' method on the DynamoDbTable instance.
    customerDynamoDbTable.createTable();
    waiter.waitUntilTableExists(b -> b.tableName(tableName));
}
```

## Gunakan perpustakaan pihak ketiga, seperti Lombok
<a name="ddb-en-client-use-immut-lombok"></a>

Perpustakaan pihak ketiga, seperti [Project Lombok](https://projectlombok.org/), membantu menghasilkan kode boilerplate yang terkait dengan objek yang tidak dapat diubah. DynamoDB Enhanced Client API bekerja dengan pustaka ini selama kelas data mengikuti konvensi yang dirinci di bagian ini. 

Contoh berikut menunjukkan `CustomerImmutable` kelas abadi dengan anotasi Lombok. Perhatikan bagaimana `onMethod` fitur Lombok menyalin anotasi DynamoDB berbasis atribut, seperti, ke kode yang dihasilkan. `@DynamoDbPartitionKey`

```
@Value
@Builder
@DynamoDbImmutable(builder = Customer.CustomerBuilder.class)
public class Customer {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;

    @Getter(onMethod_=@DynamoDbSortKey)
    private String email;

    @Getter(onMethod_=@DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name"))
    private String name;

    @Getter(onMethod_=@DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"}))
    private Instant createdDate;
}
```

# Gunakan ekspresi dan kondisi
<a name="ddb-en-client-expressions"></a>

[Ekspresi dalam DynamoDB Enhanced Client API adalah representasi Java dari ekspresi DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)

DynamoDB Enhanced Client API menggunakan tiga jenis ekspresi:

[Ekspresi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)  
`Expression`Kelas digunakan ketika Anda menentukan kondisi dan filter.

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)  
Jenis ekspresi ini merupakan [kondisi utama](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) untuk operasi kueri.

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)  
Kelas ini membantu Anda menulis ekspresi [pembaruan DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) dan saat ini digunakan dalam kerangka ekstensi saat Anda memperbarui item.

## Anatomi ekspresi
<a name="ddb-en-client-expressions-compoonents"></a>

Ekspresi terdiri dari yang berikut:
+ Ekspresi string (wajib). String berisi ekspresi logika DynamoDB dengan nama placeholder untuk nama atribut dan nilai atribut.
+ Peta nilai ekspresi (biasanya diperlukan).
+ Peta nama ekspresi (opsional).

Gunakan pembangun untuk menghasilkan `Expression` objek yang mengambil bentuk umum berikut.

```
Expression expression = Expression.builder()
                            .expression(<String>)
                            .expressionNames(<Map>)
                            .expressionValues(<Map>)
                           .build()
```

`Expression`S biasanya membutuhkan peta nilai ekspresi. Peta memberikan nilai untuk placeholder dalam ekspresi string. Kunci peta terdiri dari nama placeholder yang didahului dengan titik dua (`:`) dan nilai peta adalah instance dari. [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html) [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/AttributeValues.html)Kelas memiliki metode kenyamanan untuk menghasilkan `AttributeValue` instance dari literal. Atau, Anda dapat menggunakan `AttributeValue.Builder` untuk menghasilkan `AttributeValue` instance.

Cuplikan berikut menunjukkan peta dengan dua entri setelah baris komentar 2. String diteruskan ke `expression()` metode, ditampilkan setelah baris komentar 1, berisi placeholder yang DynamoDB menyelesaikan sebelum melakukan operasi. Cuplikan ini tidak berisi peta nama ekspresi, karena *harga* adalah nama atribut yang diizinkan.

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();
```

Jika nama atribut dalam tabel DynamoDB adalah kata cadangan, dimulai dengan angka, atau berisi spasi, peta nama ekspresi diperlukan untuk. `Expression`

Misalnya, jika nama atribut `1price` bukan `price` dalam contoh kode sebelumnya, contoh akan perlu dimodifikasi seperti yang ditunjukkan pada contoh berikut.

```
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .filterExpression(Expression.builder()
                        .expression("#price >= :min_value AND #price <= :max_value")
                        .expressionNames( Map.of("#price", "1price") )
                        .expressionValues(
                                Map.of(":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();
```

Sebuah placeholder untuk nama ekspresi dimulai dengan tanda pound ()`#`. Entri untuk peta nama ekspresi menggunakan placeholder sebagai kunci dan nama atribut sebagai nilai. Peta ditambahkan ke pembuat ekspresi dengan `expressionNames()` metode. DynamoDB menyelesaikan nama atribut sebelum melakukan operasi.

Nilai ekspresi tidak diperlukan jika fungsi digunakan dalam ekspresi string. Contoh fungsi ekspresi adalah`attribute_exists(<attribute_name>)`.

Contoh berikut membangun sebuah `Expression` yang menggunakan fungsi [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions). String ekspresi dalam contoh ini tidak menggunakan placeholder. Ekspresi ini dapat digunakan pada `putItem` operasi untuk memeriksa apakah item sudah ada dalam database dengan nilai `movie` atribut sama dengan `movie` atribut objek data.

```
Expression exp = Expression.builder().expression("attribute_not_exists (movie)").build();
```

Panduan Pengembang DynamoDB berisi informasi lengkap tentang ekspresi [tingkat rendah yang](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html) digunakan dengan DynamoDB.

## Ekspresi kondisi dan kondisional
<a name="ddb-en-client-expressions-cond"></a>

Ketika Anda menggunakan`putItem()`,`updateItem()`, dan `deleteItem()` metode, dan juga ketika Anda menggunakan transaksi dan operasi batch, Anda menggunakan `[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)` objek untuk menentukan kondisi yang DynamoDB harus memenuhi untuk melanjutkan operasi. Ekspresi ini diberi nama ekspresi kondisi. Sebagai contoh, lihat ekspresi kondisi yang digunakan dalam `addDeleteItem()` metode (setelah baris komentar 1) dari [contoh transaksi](ddb-en-client-use-multiop-trans.md#ddb-en-client-use-multiop-trans-writeitems-opcondition) yang ditunjukkan dalam panduan ini.

Ketika Anda bekerja dengan `query()` metode, suatu kondisi dinyatakan sebagai a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html). `QueryConditional`Kelas memiliki beberapa metode kenyamanan statis yang membantu Anda menulis kriteria yang menentukan item mana yang akan dibaca dari DynamoDB.

Sebagai contoh`QueryConditionals`, lihat contoh kode pertama dari [`Query`contoh metode](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-query-example) bagian panduan ini.

## Ekspresi Filter
<a name="ddb-en-client-expressions-filter"></a>

Ekspresi filter digunakan dalam operasi pemindaian dan kueri untuk memfilter item yang dikembalikan. 

Ekspresi filter diterapkan setelah semua data dibaca dari database, sehingga biaya baca sama seperti jika tidak ada filter. [Panduan *Pengembang Amazon DynamoDB* memiliki informasi lebih lanjut tentang penggunaan ekspresi filter untuk operasi kueri [dan](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.FilterExpression) pemindaian.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.FilterExpression)

Contoh berikut menunjukkan ekspresi filter ditambahkan ke permintaan scan. Kriteria membatasi barang yang dikembalikan ke barang dengan harga antara 8.00 dan 80,00 inklusif.

```
        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();
```

## Ekspresi pembaruan
<a name="ddb-en-client-expressions-update"></a>

Metode DynamoDB Enhanced Client `updateItem()` menyediakan cara standar untuk memperbarui item di DynamoDB. [Namun, ketika Anda memerlukan lebih banyak fungsionalitas, [UpdateExpressions](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)berikan representasi type-safe dari sintaks ekspresi pembaruan DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) Misalnya, Anda dapat menggunakan `UpdateExpressions` untuk meningkatkan nilai tanpa terlebih dahulu membaca item dari DynamoDB, atau menambahkan anggota individu ke daftar. Ekspresi pembaruan saat ini tersedia di ekstensi khusus untuk `updateItem()` metode ini.

Untuk contoh yang menggunakan ekspresi pembaruan, lihat [contoh ekstensi kustom](ddb-en-client-extensions-custom.md) dalam panduan ini.

Informasi selengkapnya tentang ekspresi pembaruan tersedia di Panduan Pengembang [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

# Bekerja dengan hasil paginasi: pemindaian dan kueri
<a name="ddb-en-client-use-multirecord"></a>

*Metode`scan`, `query` dan `batch` metode DynamoDB Enhanced Client API mengembalikan respons dengan satu halaman atau beberapa.* Sebuah halaman berisi satu atau lebih item. Kode Anda dapat memproses respons per halaman atau dapat memproses item individual.

Respons paginasi yang dikembalikan oleh `DynamoDbEnhancedClient` klien sinkron mengembalikan [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)objek, sedangkan respons yang dikembalikan oleh `DynamoDbEnhancedAsyncClient` asinkron mengembalikan objek. [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Bagian ini melihat pemrosesan hasil paginasi dan memberikan contoh yang menggunakan pemindaian dan kueri APIs.

## Memindai tabel
<a name="ddb-en-client-use-multirecord-scan"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer))Metode SDK sesuai dengan operasi [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) dengan nama yang sama. DynamoDB Enhanced Client API menawarkan opsi yang sama tetapi menggunakan model objek yang sudah dikenal dan menangani pagination untuk Anda.

Pertama, kita menjelajahi `PageIterable` antarmuka dengan melihat `scan` metode kelas pemetaan sinkron,. [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)

### Gunakan API sinkron
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

Contoh berikut menunjukkan `scan` metode yang menggunakan [ekspresi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) untuk memfilter item yang dikembalikan. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)Ini adalah objek model yang ditunjukkan sebelumnya.

Ekspresi pemfilteran yang ditampilkan setelah baris komentar 2 membatasi `ProductCatalog` item yang dikembalikan ke item dengan nilai harga antara 8,00 dan 80,00 secara inklusif.

Contoh ini juga mengecualikan `isbn` nilai dengan menggunakan `attributesToProject` metode yang ditampilkan setelah baris komentar 1.

Setelah komentar baris 3, `PageIterable` objek`pagedResults`,, dikembalikan oleh `scan` metode. `stream`Metode `PageIterable` mengembalikan [https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)objek, yang dapat Anda gunakan untuk memproses halaman. Dalam contoh ini, jumlah halaman dihitung dan dicatat.

Dimulai dengan baris komentar 4, contoh menunjukkan dua variasi mengakses `ProductCatalog` item. Versi setelah baris komentar 4a mengalir melalui setiap halaman dan mengurutkan dan mencatat item di setiap halaman. Versi setelah baris komentar 4b melewatkan iterasi halaman dan mengakses item secara langsung.

`PageIterable`Antarmuka menawarkan beberapa cara untuk memproses hasil karena dua antarmuka induknya— [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)dan [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html). `Iterable`membawa`forEach`, `iterator` dan `spliterator` metode, dan `SdkIterable` membawa `stream` metode.

```
    public static void scanSync(DynamoDbTable<ProductCatalog> productCatalog) {

        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();

        // 3. A PageIterable object is returned by the scan method.
        PageIterable<ProductCatalog> pagedResults = productCatalog.scan(request);
        logger.info("page count: {}", pagedResults.stream().count());

        // 4. Log the returned ProductCatalog items using two variations.
        // 4a. This version sorts and logs the items of each page.
        pagedResults.stream().forEach(p -> p.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                ));
        // 4b. This version sorts and logs all items for all pages.
        pagedResults.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                );
    }
```

### Gunakan API asinkron
<a name="ddb-en-client-use-multirecord-scan-async"></a>

`scan`Metode asinkron mengembalikan hasil sebagai objek. `PagePublisher` `PagePublisher`Antarmuka memiliki dua `subscribe` metode yang dapat Anda gunakan untuk memproses halaman respons. Salah satu `subscribe` metode berasal dari antarmuka `org.reactivestreams.Publisher` induk. Untuk memproses halaman menggunakan opsi pertama ini, berikan `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` instance ke `subscribe` metode. Contoh pertama yang berikut menunjukkan penggunaan `subscribe` metode.

`subscribe`Metode kedua berasal dari [SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)antarmuka. Versi ini `subscribe` menerima [https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html)bukan a`Subscriber`. Variasi `subscribe` metode ini ditunjukkan pada contoh kedua berikut.

Contoh berikut menunjukkan versi asinkron dari `scan` metode yang menggunakan ekspresi filter yang sama yang ditunjukkan pada contoh sebelumnya. 

Setelah baris komentar 3, `DynamoDbAsyncTable.scan` mengembalikan `PagePublisher` objek. Pada baris berikutnya, kode membuat instance `org.reactivestreams.Subscriber` antarmuka,`ProductCatalogSubscriber`, yang berlangganan baris `PagePublisher` setelah komentar 4.

`Subscriber`Objek mengumpulkan `ProductCatalog` item dari setiap halaman dalam `onNext` metode setelah baris komentar 8 dalam contoh `ProductCatalogSubscriber` kelas. Item disimpan dalam `List` variabel pribadi dan diakses dalam kode panggilan dengan `ProductCatalogSubscriber.getSubscribedItems()` metode. Ini disebut setelah baris komentar 5.

Setelah daftar diambil, kode mengurutkan semua `ProductCatalog` item berdasarkan harga dan mencatat setiap item.

[CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)Di `ProductCatalogSubscriber` kelas memblokir thread panggilan sampai semua item telah ditambahkan ke daftar sebelum melanjutkan setelah baris komentar 5. 

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();

        // 3. A PagePublisher object is returned by the scan method.
        PagePublisher<ProductCatalog> pagePublisher = productCatalog.scan(request);
        ProductCatalogSubscriber subscriber = new ProductCatalogSubscriber();
        // 4. Subscribe the ProductCatalogSubscriber to the PagePublisher.
        pagePublisher.subscribe(subscriber);
        // 5. Retrieve all collected ProductCatalog items accumulated by the subscriber.
        subscriber.getSubscribedItems().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(item ->
                        logger.info(item.toString()));
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
    }
```

```
    private static class ProductCatalogSubscriber implements Subscriber<Page<ProductCatalog>> {
        private CountDownLatch latch = new CountDownLatch(1);
        private Subscription subscription;
        private List<ProductCatalog> itemsFromAllPages = new ArrayList<>();

        @Override
        public void onSubscribe(Subscription sub) {
            subscription = sub;
            subscription.request(1L);
            try {
                latch.await(); // Called by main thread blocking it until latch is released.
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onNext(Page<ProductCatalog> productCatalogPage) {
            // 8. Collect all the ProductCatalog instances in the page, then ask the publisher for one more page.
            itemsFromAllPages.addAll(productCatalogPage.items());
            subscription.request(1L);
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onComplete() {
            latch.countDown(); // Call by subscription thread; latch releases.
        }

        List<ProductCatalog> getSubscribedItems() {
            return this.itemsFromAllPages;
        }
    }
```

Contoh cuplikan berikut menggunakan versi `PagePublisher.subscribe` metode yang menerima baris `Consumer` setelah komentar 6. Parameter lambda Java mengkonsumsi halaman, yang selanjutnya memproses setiap item. Dalam contoh ini, setiap halaman diproses dan item pada setiap halaman diurutkan dan kemudian dicatat.

```
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

`items`Metode `PagePublisher` membuka bungkus contoh model sehingga kode Anda dapat memproses item secara langsung. Pendekatan ini ditunjukkan dalam cuplikan berikut.

```
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

## Mengkueri Tabel
<a name="ddb-en-client-use-multirecord-query"></a>

Anda dapat menggunakan DynamoDB Enhanced Client untuk menanyakan tabel Anda dan mengambil beberapa item yang cocok dengan kriteria tertentu. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest))Metode ini menemukan item berdasarkan nilai kunci primer menggunakan `@DynamoDbPartitionKey` dan `@DynamoDbSortKey` anotasi opsional yang ditentukan pada kelas data Anda.

`query()`Metode ini memerlukan nilai kunci partisi dan secara opsional menerima kondisi kunci pengurutan untuk lebih menyempurnakan hasil. Seperti `scan` API, kueri mengembalikan a `PageIterable` untuk panggilan sinkron dan a `PagePublisher` untuk panggilan asinkron.

### `Query`contoh metode
<a name="ddb-en-client-use-multirecord-query-example"></a>

Contoh kode `query()` metode yang mengikuti menggunakan `MovieActor` kelas. Kelas data mendefinisikan kunci primer komposit yang terdiri dari **`movie`**atribut sebagai kunci partisi dan **`actor`**atribut sebagai kunci pengurutan. 

#### `MovieActor` kelas
<a name="ddb-en-client-use-movieactor-class"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.Objects;

@DynamoDbBean
public class MovieActor implements Comparable<MovieActor> {

    private String movieName;
    private String actorName;
    private String actingAward;
    private Integer actingYear;
    private String actingSchoolName;

    @DynamoDbPartitionKey
    @DynamoDbAttribute("movie")
    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute("actor")
    public String getActorName() {
        return actorName;
    }

    public void setActorName(String actorName) {
        this.actorName = actorName;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "acting_award_year")
    @DynamoDbAttribute("actingaward")
    public String getActingAward() {
        return actingAward;
    }

    public void setActingAward(String actingAward) {
        this.actingAward = actingAward;
    }

    @DynamoDbSecondarySortKey(indexNames = {"acting_award_year", "movie_year"})
    @DynamoDbAttribute("actingyear")
    public Integer getActingYear() {
        return actingYear;
    }

    public void setActingYear(Integer actingYear) {
        this.actingYear = actingYear;
    }

    @DynamoDbAttribute("actingschoolname")
    public String getActingSchoolName() {
        return actingSchoolName;
    }

    public void setActingSchoolName(String actingSchoolName) {
        this.actingSchoolName = actingSchoolName;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("MovieActor{");
        sb.append("movieName='").append(movieName).append('\'');
        sb.append(", actorName='").append(actorName).append('\'');
        sb.append(", actingAward='").append(actingAward).append('\'');
        sb.append(", actingYear=").append(actingYear);
        sb.append(", actingSchoolName='").append(actingSchoolName).append('\'');
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MovieActor that = (MovieActor) o;
        return Objects.equals(movieName, that.movieName) && Objects.equals(actorName, that.actorName) && Objects.equals(actingAward, that.actingAward) && Objects.equals(actingYear, that.actingYear) && Objects.equals(actingSchoolName, that.actingSchoolName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(movieName, actorName, actingAward, actingYear, actingSchoolName);
    }

    @Override
    public int compareTo(MovieActor o) {
        if (this.movieName.compareTo(o.movieName) != 0){
            return this.movieName.compareTo(o.movieName);
        } else {
            return this.actorName.compareTo(o.actorName);
        }
    }
}
```

Contoh kode yang mengikuti kueri terhadap item berikut.

#### Item dalam `MovieActor` tabel
<a name="ddb-en-client-use-movieactor-items"></a>

```
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie02', actorName='actor0', actingAward='actingaward0', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor1', actingAward='actingaward1', actingYear=2002, actingSchoolName='actingschool1'}
MovieActor{movieName='movie02', actorName='actor2', actingAward='actingaward2', actingYear=2002, actingSchoolName='actingschool2'}
MovieActor{movieName='movie02', actorName='actor3', actingAward='actingaward3', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor4', actingAward='actingaward4', actingYear=2002, actingSchoolName='actingschool4'}
MovieActor{movieName='movie03', actorName='actor0', actingAward='actingaward0', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor1', actingAward='actingaward1', actingYear=2003, actingSchoolName='actingschool1'}
MovieActor{movieName='movie03', actorName='actor2', actingAward='actingaward2', actingYear=2003, actingSchoolName='actingschool2'}
MovieActor{movieName='movie03', actorName='actor3', actingAward='actingaward3', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor4', actingAward='actingaward4', actingYear=2003, actingSchoolName='actingschool4'}
```

Kode berikut mendefinisikan dua `QueryConditional` contoh: `keyEqual` (setelah baris komentar 1) dan `sortGreaterThanOrEqualTo` (setelah baris komentar 1a).

#### Item kueri dengan kunci partisi
<a name="keyEqual-query-conditional-example"></a>

`keyEqual`Instance mencocokkan item dengan nilai kunci partisi dari **`movie01`**. 

Contoh ini juga mendefinisikan ekspresi filter setelah baris komentar 2 yang menyaring item apa pun yang tidak memiliki **`actingschoolname`**nilai.

`QueryEnhancedRequest`Menggabungkan kondisi kunci dan ekspresi filter untuk kueri.

```
    public static void query(DynamoDbTable movieActorTable) {

        // 1. Define a QueryConditional instance to return items matching a partition value.
        QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b.partitionValue("movie01"));
        // 1a. Define a QueryConditional that adds a sort key criteria to the partition value criteria.
        QueryConditional sortGreaterThanOrEqualTo = QueryConditional.sortGreaterThanOrEqualTo(b -> b.partitionValue("movie01").sortValue("actor2"));
        // 2. Define a filter expression that filters out items whose attribute value is null.
        final Expression filterOutNoActingschoolname = Expression.builder().expression("attribute_exists(actingschoolname)").build();

        // 3. Build the query request.
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(keyEqual)
                .filterExpression(filterOutNoActingschoolname)
                .build();
        // 4. Perform the query using the "keyEqual" conditional and filter expression.
        PageIterable<MovieActor> pagedResults = movieActorTable.query(tableQuery);
        logger.info("page count: {}", pagedResults.stream().count()); // Log  number of pages.

        pagedResults.items().stream()
                .sorted()
                .forEach(
                        item -> logger.info(item.toString()) // Log the sorted list of items.
                );
```

**Example — Output menggunakan `keyEqual` query kondisional**  
Berikut ini adalah output dari menjalankan metode. Output menampilkan item dengan `movieName` nilai **movie01** dan tidak menampilkan item yang `actingSchoolName` sama dengan. **`null`**  

```
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

#### Item kueri dengan kunci partisi dan kunci sortir
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo``QueryConditional`**Menyempurnakan kecocokan kunci partisi (**movie01**) dengan menambahkan kondisi kunci pengurutan untuk nilai yang lebih besar dari atau sama dengan aktor2.**

[`QueryConditional`metode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) yang dimulai dengan `sort` memerlukan nilai kunci partisi untuk mencocokkan dan selanjutnya menyempurnakan kueri dengan perbandingan berdasarkan nilai kunci sortir. `Sort`dalam nama metode tidak berarti hasilnya diurutkan, tetapi nilai kunci sortir akan digunakan untuk perbandingan.

Dalam cuplikan berikut, kami mengubah permintaan kueri yang ditampilkan sebelumnya setelah baris komentar 3. Cuplikan ini menggantikan kueri “KeyEqual” bersyarat dengan syarat kueri "sortGreaterThanOrEqualTo" yang ditentukan setelah baris komentar 1a. Kode berikut juga menghapus ekspresi filter.

```
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(sortGreaterThanOrEqualTo).build();
```

**Example — Output menggunakan `sortGreaterThanOrEqualTo` query kondisional**  
Output berikut menampilkan hasil dari query. **Kueri mengembalikan item yang memiliki `movieName` nilai sama dengan **movie01** dan hanya item yang memiliki `actorName` nilai yang lebih besar dari atau sama dengan actor2.** Karena kita menghapus filter, query mengembalikan item yang tidak memiliki nilai untuk `actingSchoolName` atribut.  

```
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

# Lakukan operasi batch
<a name="ddb-en-client-use-multiop-batch"></a>

[DynamoDB Enhanced Client API menawarkan dua metode batch [`batchGetItem`, () dan (](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)))`batchWriteItem`.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchWriteItem(java.util.function.Consumer))

## Contoh `batchGetItem()`
<a name="ddb-en-client-use-multiop-batch-get"></a>

Dengan [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer))metode ini, Anda dapat mengambil hingga 100 item individual di beberapa tabel dalam satu permintaan keseluruhan. Contoh berikut menggunakan kelas [`Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)dan [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)data yang ditunjukkan sebelumnya.

Dalam contoh setelah baris 1 dan 2, Anda membangun `[ReadBatch](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ReadBatch.html)` objek yang kemudian Anda tambahkan sebagai parameter ke `batchGetItem()` metode setelah baris komentar 3. 

Kode setelah baris komentar 1 membangun batch untuk dibaca dari `Customer` tabel. Kode setelah baris komentar 1a menunjukkan penggunaan `[GetItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/GetItemEnhancedRequest.Builder.html)` pembangun yang mengambil nilai kunci primer dan nilai kunci pengurutan untuk menentukan item yang akan dibaca. Jika kelas data memiliki kunci komposit, Anda harus memberikan nilai kunci partisi dan nilai kunci sortir. 

Berbeda dengan menentukan nilai kunci untuk meminta item, Anda dapat menggunakan kelas data untuk meminta item seperti yang ditunjukkan setelah baris komentar 1b. SDK mengekstrak nilai kunci di balik layar sebelum mengirimkan permintaan.

[Saat Anda menentukan item menggunakan pendekatan berbasis kunci seperti yang ditunjukkan dalam dua pernyataan setelah 2a, Anda juga dapat menentukan bahwa DynamoDB harus melakukan pembacaan yang sangat konsisten.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html) Ketika `consistentRead()` metode ini digunakan, itu harus digunakan pada semua item yang diminta untuk tabel yang sama.

Untuk mengambil item yang DynamoDB temukan, gunakan metode `[resultsForTable() ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#resultsForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` yang ditampilkan setelah baris komentar 4. Panggil metode untuk setiap tabel yang dibaca dalam permintaan. `resultsForTable()`mengembalikan daftar item yang ditemukan yang dapat Anda proses menggunakan `java.util.List` metode apapun. Contoh ini mencatat setiap item.

Untuk menemukan item yang DynamoDB tidak memproses, gunakan pendekatan setelah baris komentar 5. `BatchGetResultPage`Kelas memiliki `[unprocessedKeysForTable()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#unprocessedKeysForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` metode yang memberi Anda akses ke setiap kunci yang belum diproses. [Referensi BatchGetItem API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) memiliki informasi lebih lanjut tentang situasi yang menghasilkan item yang tidak diproses.

```
    public static void batchGetItemExample(DynamoDbEnhancedClient enhancedClient,
                                           DynamoDbTable<Customer> customerTable,
                                           DynamoDbTable<MovieActor> movieActorTable) {

        Customer customer2 = new Customer();
        customer2.setId("2");
        customer2.setEmail("cust2@example.org");

        // 1. Build a batch to read from the Customer table.
        ReadBatch customerBatch = ReadBatch.builder(Customer.class)
                .mappedTableResource(customerTable)
                // 1a. Specify the primary key value and sort key value for the item.
                .addGetItem(b -> b.key(k -> k.partitionValue("1").sortValue("cust1@orgname.org")))
                // 1b. Alternatively, supply a data class instances to provide the primary key values.
                .addGetItem(customer2)
                .build();

        // 2. Build a batch to read from the MovieActor table.
        ReadBatch moveActorBatch = ReadBatch.builder(MovieActor.class)
                .mappedTableResource(movieActorTable)
                // 2a. Call consistentRead(Boolean.TRUE) for each item for the same table.
                .addGetItem(b -> b.key(k -> k.partitionValue("movie01").sortValue("actor1")).consistentRead(Boolean.TRUE))
                .addGetItem(b -> b.key(k -> k.partitionValue("movie01").sortValue("actor4")).consistentRead(Boolean.TRUE))
                .build();

        // 3. Add ReadBatch objects to the request.
        BatchGetResultPageIterable resultPages = enhancedClient.batchGetItem(b -> b.readBatches(customerBatch, moveActorBatch));

        // 4. Retrieve the successfully requested items from each table.
        resultPages.resultsForTable(customerTable).forEach(item -> logger.info(item.toString()));
        resultPages.resultsForTable(movieActorTable).forEach(item -> logger.info(item.toString()));

        // 5. Retrieve the keys of the items requested but not processed by the service.
        resultPages.forEach((BatchGetResultPage pageResult) -> {
            pageResult.unprocessedKeysForTable(customerTable).forEach(key -> logger.info("Unprocessed item key: " + key.toString()));
            pageResult.unprocessedKeysForTable(movieActorTable).forEach(key -> logger.info("Unprocessed item key: " + key.toString()));
        });
    }
```

Asumsikan bahwa item berikut ada di dua tabel sebelum menjalankan kode contoh.

### Item dalam tabel
<a name="ddb-en-client-use-multiop-batch-get-tableitems"></a>

```
Customer [id=1, name=CustName1, email=cust1@example.org, regDate=2023-03-31T15:46:27.688Z]
Customer [id=2, name=CustName2, email=cust2@example.org, regDate=2023-03-31T15:46:28.688Z]
Customer [id=3, name=CustName3, email=cust3@example.org, regDate=2023-03-31T15:46:29.688Z]
Customer [id=4, name=CustName4, email=cust4@example.org, regDate=2023-03-31T15:46:30.688Z]
Customer [id=5, name=CustName5, email=cust5@example.org, regDate=2023-03-31T15:46:31.689Z]
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

Output berikut menunjukkan item yang dikembalikan dan dicatat setelah baris komentar 4.

```
Customer [id=1, name=CustName1, email=cust1@example.org, regDate=2023-03-31T15:46:27.688Z]
Customer [id=2, name=CustName2, email=cust2@example.org, regDate=2023-03-31T15:46:28.688Z]
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
```

## Contoh `batchWriteItem()`
<a name="ddb-en-client-use-multiop-batch-write"></a>

`batchWriteItem()`Metode ini menempatkan atau menghapus beberapa item dalam satu atau lebih tabel. Anda dapat menentukan hingga 25 operasi put atau hapus individu dalam permintaan. Contoh berikut menggunakan kelas [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)dan [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)model yang ditunjukkan sebelumnya.

`WriteBatch`objek dibangun setelah baris komentar 1 dan 2. Untuk `ProductCatalog` tabel, kode menempatkan satu item dan menghapus satu item. Untuk `MovieActor` tabel setelah baris komentar 2, kode menempatkan dua item dan menghapus satu.

`batchWriteItem`Metode ini disebut setelah baris komentar 3. `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteItemEnhancedRequest.Builder.html)`Parameter menyediakan permintaan batch untuk setiap tabel.

`[BatchWriteResult](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteResult.html)`Objek yang dikembalikan menyediakan metode terpisah untuk setiap operasi untuk melihat permintaan yang belum diproses. Kode setelah baris komentar 4a menyediakan kunci untuk permintaan penghapusan yang belum diproses dan kode setelah baris komentar 4b menyediakan item put yang belum diproses.

```
    public static void batchWriteItemExample(DynamoDbEnhancedClient enhancedClient,
                                             DynamoDbTable<ProductCatalog> catalogTable,
                                             DynamoDbTable<MovieActor> movieActorTable) {

        // 1. Build a batch to write to the ProductCatalog table.
        WriteBatch products = WriteBatch.builder(ProductCatalog.class)
                .mappedTableResource(catalogTable)
                .addPutItem(b -> b.item(getProductCatItem1()))
                .addDeleteItem(b -> b.key(k -> k
                        .partitionValue(getProductCatItem2().id())
                        .sortValue(getProductCatItem2().title())))
                .build();

        // 2. Build a batch to write to the MovieActor table.
        WriteBatch movies = WriteBatch.builder(MovieActor.class)
                .mappedTableResource(movieActorTable)
                .addPutItem(getMovieActorYeoh())
                .addPutItem(getMovieActorBlanchettPartial())
                .addDeleteItem(b -> b.key(k -> k
                        .partitionValue(getMovieActorStreep().getMovieName())
                        .sortValue(getMovieActorStreep().getActorName())))
                .build();

        // 3. Add WriteBatch objects to the request.
        BatchWriteResult batchWriteResult = enhancedClient.batchWriteItem(b -> b.writeBatches(products, movies));
        // 4. Retrieve keys for items the service did not process.
        // 4a. 'unprocessedDeleteItemsForTable()' returns keys for delete requests that did not process.
        if (batchWriteResult.unprocessedDeleteItemsForTable(movieActorTable).size() > 0) {
            batchWriteResult.unprocessedDeleteItemsForTable(movieActorTable).forEach(key ->
                    logger.info(key.toString()));
        }
        // 4b. 'unprocessedPutItemsForTable()' returns keys for put requests that did not process.
        if (batchWriteResult.unprocessedPutItemsForTable(catalogTable).size() > 0) {
            batchWriteResult.unprocessedPutItemsForTable(catalogTable).forEach(key ->
                    logger.info(key.toString()));
        }
    }
```

Metode pembantu berikut menyediakan objek model untuk operasi put dan delete.

### Metode pembantu
<a name="ddb-en-client-use-multiop-batch-write-helpers"></a>

```
 1.     public static ProductCatalog getProductCatItem1() {
 2.         return ProductCatalog.builder()
 3.                 .id(2)
 4.                 .isbn("1-565-85698")
 5.                 .authors(new HashSet<>(Arrays.asList("a", "b")))
 6.                 .price(BigDecimal.valueOf(30.22))
 7.                 .title("Title 55")
 8.                 .build();
 9.     }
10. 
11.     public static ProductCatalog getProductCatItem2() {
12.         return ProductCatalog.builder()
13.                 .id(4)
14.                 .price(BigDecimal.valueOf(40.00))
15.                 .title("Title 1")
16.                 .build();
17.     }  
18. 
19.     public static MovieActor getMovieActorBlanchettPartial() {
20.         MovieActor movieActor = new MovieActor();
21.         movieActor.setActorName("Cate Blanchett");
22.         movieActor.setMovieName("Blue Jasmine");
23.         movieActor.setActingYear(2023);
24.         movieActor.setActingAward("Best Actress");
25.         return movieActor;
26.     }
27. 
28.     public static MovieActor getMovieActorStreep() {
29.         MovieActor movieActor = new MovieActor();
30.         movieActor.setActorName("Meryl Streep");
31.         movieActor.setMovieName("Sophie's Choice");
32.         movieActor.setActingYear(1982);
33.         movieActor.setActingAward("Best Actress");
34.         movieActor.setActingSchoolName("Yale School of Drama");
35.         return movieActor;
36.     }
37. 
38.     public static MovieActor getMovieActorYeoh(){
39.         MovieActor movieActor = new MovieActor();
40.         movieActor.setActorName("Michelle Yeoh");
41.         movieActor.setMovieName("Everything Everywhere All at Once");
42.         movieActor.setActingYear(2023);
43.         movieActor.setActingAward("Best Actress");
44.         movieActor.setActingSchoolName("Royal Academy of Dance");
45.         return movieActor;
46.     }
```

Asumsikan bahwa tabel berisi item berikut sebelum Anda menjalankan kode contoh.

```
MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
```

Setelah kode contoh selesai, tabel berisi item berikut.

```
MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='null'}
MovieActor{movieName='Everything Everywhere All at Once', actorName='Michelle Yeoh', actingAward='Best Actress', actingYear=2023, actingSchoolName='Royal Academy of Dance'}
ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
```

Perhatikan dalam `MovieActor` tabel bahwa item `Blue Jasmine` film telah diganti dengan item yang digunakan dalam permintaan put yang diperoleh melalui metode `getMovieActorBlanchettPartial()` pembantu. Jika nilai atribut kacang data tidak disediakan, nilai dalam database dihapus. Inilah sebabnya mengapa hasilnya `actingSchoolName` nol untuk item `Blue Jasmine` film.

**catatan**  
Meskipun dokumentasi API menunjukkan bahwa ekspresi kondisi dapat digunakan dan bahwa kapasitas yang dikonsumsi serta metrik pengumpulan dapat dikembalikan dengan permintaan [put](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PutItemEnhancedRequest.html) dan [delete](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.html) individual, ini tidak terjadi dalam skenario penulisan batch. Untuk meningkatkan kinerja operasi batch, opsi individual ini diabaikan.

# Lakukan operasi transaksi
<a name="ddb-en-client-use-multiop-trans"></a>

DynamoDB Enhanced Client API menyediakan dan metode`transactGetItems()`. `transactWriteItems()` Metode transaksi SDK for Java memberikan atomisitas, konsistensi, isolasi, dan daya tahan (ACID) dalam tabel DynamoDB, membantu Anda menjaga kebenaran data dalam aplikasi Anda.

## Contoh `transactGetItems()`
<a name="ddb-en-client-use-multiop-trans-getitems"></a>

`[transactGetItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactGetItems(java.util.function.Consumer))`Metode ini menerima hingga 100 permintaan individu untuk item. Semua item dibaca dalam satu transaksi atom. Panduan *Pengembang Amazon DynamoDB* memiliki informasi tentang [kondisi yang menyebabkan `transactGetItems()` metode gagal](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txgetitems), dan juga tentang tingkat isolasi yang digunakan saat Anda menelepon. `[transactGetItem()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-isolation)`

Setelah baris komentar 1 dalam contoh berikut, kode memanggil `transactGetItems()` metode dengan `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html)` parameter. Builder `[addGetItem()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html#addGetItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource,T))` dipanggil tiga kali dengan objek data yang berisi nilai kunci yang akan digunakan SDK untuk menghasilkan permintaan akhir.

Permintaan mengembalikan daftar `[Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html)` objek setelah baris komentar 2. Daftar dokumen yang dikembalikan berisi contoh [dokumen](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html) non-null dari data item dalam urutan yang sama seperti yang diminta. `[Document.getItem(MappedTableResource<T> mappedTableResource)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html#getItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))`Metode mengkonversi objek untyped menjadi `Document` objek Java diketik jika data item dikembalikan, jika tidak metode mengembalikan null.

```
    public static void transactGetItemsExample(DynamoDbEnhancedClient enhancedClient,
                                               DynamoDbTable<ProductCatalog> catalogTable,
                                               DynamoDbTable<MovieActor> movieActorTable) {

        // 1. Request three items from two tables using a builder.
        final List<Document> documents = enhancedClient.transactGetItems(b -> b
                .addGetItem(catalogTable, Key.builder().partitionValue(2).sortValue("Title 55").build())
                .addGetItem(movieActorTable, Key.builder().partitionValue("Sophie's Choice").sortValue("Meryl Streep").build())
                .addGetItem(movieActorTable, Key.builder().partitionValue("Blue Jasmine").sortValue("Cate Blanchett").build())
                .build());

        // 2. A list of Document objects is returned in the same order as requested.
        ProductCatalog title55 = documents.get(0).getItem(catalogTable);
        if (title55 != null) {
            logger.info(title55.toString());
        }

        MovieActor sophiesChoice = documents.get(1).getItem(movieActorTable);
        if (sophiesChoice != null) {
            logger.info(sophiesChoice.toString());
        }

        // 3. The getItem() method returns null if the Document object contains no item from DynamoDB.
        MovieActor blueJasmine = documents.get(2).getItem(movieActorTable);
        if (blueJasmine != null) {
            logger.info(blueJasmine.toString());
        }
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

Output berikut dicatat. Jika item diminta tetapi tidak ditemukan, itu tidak dikembalikan seperti halnya permintaan untuk film bernama`Blue Jasmine`.

```
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

## `transactWriteItems()` contoh
<a name="ddb-en-client-use-multiop-trans-writeitems"></a>

`[transactWriteItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))`Menerima hingga 100 tindakan put, update, atau delete dalam satu transaksi atom di beberapa tabel. Panduan *Pengembang Amazon DynamoDB* berisi rincian tentang pembatasan dan kondisi kegagalan operasi layanan [DynamoDB yang mendasarinya](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems).

### Contoh basic
<a name="ddb-en-client-use-multiop-trans-writeitems-basic"></a>

Dalam contoh berikut, empat operasi diminta untuk dua tabel. Kelas model yang sesuai [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)dan ditunjukkan [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)sebelumnya.

Masing-masing dari tiga kemungkinan operasi—put, update, dan delete—menggunakan parameter permintaan khusus untuk menentukan detailnya. 

Kode setelah baris komentar 1 menunjukkan variasi sederhana dari `addPutItem()` metode ini. Metode ini menerima `[MappedTableResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/MappedTableResource.html)` objek dan contoh objek data untuk dimasukkan. Pernyataan setelah komentar baris 2 menunjukkan variasi yang menerima `[TransactPutItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactPutItemEnhancedRequest.html)` instance. Variasi ini memungkinkan Anda menambahkan lebih banyak opsi dalam permintaan, seperti ekspresi kondisi. [Contoh](#ddb-en-client-use-multiop-trans-writeitems-opcondition) selanjutnya menunjukkan ekspresi kondisi untuk operasi individu.

Operasi pembaruan diminta setelah baris komentar 3. `[TransactUpdateItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactUpdateItemEnhancedRequest.Builder.html)`memiliki `ignoreNulls()` metode yang memungkinkan Anda mengonfigurasi apa yang dilakukan SDK dengan `null` nilai pada objek model. Jika `ignoreNulls()` metode mengembalikan true, SDK tidak menghapus nilai atribut tabel untuk atribut objek data yang`null`. Jika `ignoreNulls()` metode mengembalikan false, SDK meminta layanan DynamoDB untuk menghapus atribut dari item dalam tabel. Nilai default untuk `ignoreNulls` adalah false.

Pernyataan setelah baris komentar 4 menunjukkan variasi permintaan hapus yang mengambil objek data. Klien yang disempurnakan mengekstrak nilai-nilai kunci sebelum mengirimkan permintaan akhir.

```
    public static void transactWriteItems(DynamoDbEnhancedClient enhancedClient,
                                          DynamoDbTable<ProductCatalog> catalogTable,
                                          DynamoDbTable<MovieActor> movieActorTable) {

        enhancedClient.transactWriteItems(b -> b
                // 1. Simplest variation of put item request.
                .addPutItem(catalogTable, getProductCatId2())
                // 2. Put item request variation that accommodates condition expressions.
                .addPutItem(movieActorTable, TransactPutItemEnhancedRequest.builder(MovieActor.class)
                        .item(getMovieActorStreep())
                        .conditionExpression(Expression.builder().expression("attribute_not_exists (movie)").build())
                        .build())
                // 3. Update request that does not remove attribute values on the table if the data object's value is null.
                .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                        .item(getProductCatId4ForUpdate())
                        .ignoreNulls(Boolean.TRUE)
                        .build())
                // 4. Variation of delete request that accepts a data object. The key values are extracted for the request.
                .addDeleteItem(movieActorTable, getMovieActorBlanchett())
        );
    }
```

Metode pembantu berikut menyediakan objek data untuk `add*Item` parameter.

#### Metode pembantu
<a name="ddb-en-client-use-multiop-trans-writeitems-basic-helpers"></a>

```
    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }

    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Tar");
        movieActor.setActingYear(2022);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }

    public static MovieActor getMovieActorStreep() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Meryl Streep");
        movieActor.setMovieName("Sophie's Choice");
        movieActor.setActingYear(1982);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("Yale School of Drama");
        return movieActor;
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

Item berikut ada di tabel setelah kode selesai berjalan.

```
3 | ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
4 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=40.0}
5 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

Item pada baris 2 telah dihapus dan baris 3 dan 5 menunjukkan item yang diletakkan. Baris 4 menunjukkan pembaruan baris 1. `price`Nilai adalah satu-satunya nilai yang berubah pada item. Jika `ignoreNulls()` telah mengembalikan false, baris 4 akan terlihat seperti baris berikut.

```
ProductCatalog{id=4, title='Title 1', isbn='null', authors=null, price=40.0}
```

### Contoh pemeriksaan kondisi
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond"></a>

Contoh berikut menunjukkan penggunaan pemeriksaan kondisi. Pemeriksaan kondisi digunakan untuk memeriksa apakah ada item atau untuk memeriksa kondisi atribut tertentu dari suatu item dalam database. Item yang dicek dalam pemeriksaan kondisi tidak dapat digunakan dalam operasi lain dalam transaksi.

**catatan**  
Anda tidak dapat menargetkan item yang sama dengan beberapa operasi dalam transaksi yang sama. Misalnya, Anda tidak dapat melakukan pemeriksaan kondisi dan juga mencoba memperbarui item yang sama dalam transaksi yang sama.

Contoh menunjukkan salah satu dari setiap jenis operasi dalam permintaan item tulis transaksional. Setelah baris komentar 2, `addConditionCheck()` metode memasok kondisi yang gagal transaksi jika `conditionExpression` parameter mengevaluasi`false`. Ekspresi kondisi yang dikembalikan dari metode yang ditampilkan dalam blok Metode Pembantu memeriksa apakah tahun penghargaan untuk film `Sophie's Choice` tidak sama dengan. `1982` Jika ya, ekspresi mengevaluasi `false` dan transaksi gagal.

Panduan ini membahas [ekspresi](ddb-en-client-expressions.md) secara mendalam dalam topik lain.

```
    public static void conditionCheckFailExample(DynamoDbEnhancedClient enhancedClient,
                                                 DynamoDbTable<ProductCatalog> catalogTable,
                                                 DynamoDbTable<MovieActor> movieActorTable) {

        try {
            enhancedClient.transactWriteItems(b -> b
                    // 1. Perform one of each type of operation with the next three methods.
                    .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId2()).build())
                    .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId4ForUpdate())
                            .ignoreNulls(Boolean.TRUE).build())
                    .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder()
                            .key(b1 -> b1
                                    .partitionValue(getMovieActorBlanchett().getMovieName())
                                    .sortValue(getMovieActorBlanchett().getActorName())).build())
                    // 2. Add a condition check on a table item that is not involved in another operation in this request.
                    .addConditionCheck(movieActorTable, ConditionCheck.builder()
                            .conditionExpression(buildConditionCheckExpression())
                            .key(k -> k
                                    .partitionValue("Sophie's Choice")
                                    .sortValue("Meryl Streep"))
                            // 3. Specify the request to return existing values from the item if the condition evaluates to true.
                            .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                            .build())
                    .build());
        // 4. Catch the exception if the transaction fails and log the information.
        } catch (TransactionCanceledException ex) {
            ex.cancellationReasons().stream().forEach(cancellationReason -> {
                logger.info(cancellationReason.toString());
            });
        }
    }
```

Metode pembantu berikut digunakan dalam contoh kode sebelumnya.

#### Metode pembantu
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond-helpers"></a>

```
    private static Expression buildConditionCheckExpression() {
        Map<String, AttributeValue> expressionValue = Map.of(
                ":year", numberValue(1982));

        return Expression.builder()
                .expression("actingyear <> :year")
                .expressionValues(expressionValue)
                .build();
    }

    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }

    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Blue Jasmine");
        movieActor.setActingYear(2013);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
3 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

Item berikut ada di tabel setelah kode selesai berjalan.

```
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

Item tetap tidak berubah dalam tabel karena transaksi gagal. `actingYear`Nilai untuk film `Sophie's Choice` adalah`1982`, seperti yang ditunjukkan pada baris 2 item dalam tabel sebelum `transactWriteItem()` metode dipanggil.

Untuk menangkap informasi pembatalan untuk transaksi, lampirkan panggilan `transactWriteItems()` metode dalam `try` blok dan`catch`. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TransactionCanceledException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TransactionCanceledException.html) Setelah baris komentar 4 dari contoh, kode mencatat setiap `[CancellationReason](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CancellationReason.html)` objek. Karena kode berikut baris komentar 3 dari contoh menentukan bahwa nilai harus dikembalikan untuk item yang menyebabkan transaksi gagal, log menampilkan nilai database mentah untuk item `Sophie's Choice` film.

```
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Item={actor=AttributeValue(S=Meryl Streep), movie=AttributeValue(S=Sophie's Choice), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=1982), actingschoolname=AttributeValue(S=Yale School of Drama)}, ¬
    Code=ConditionalCheckFailed, Message=The conditional request failed.)
```

### Contoh kondisi operasi tunggal
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition"></a>

Contoh berikut menunjukkan penggunaan kondisi pada operasi tunggal dalam permintaan transaksi. Operasi hapus setelah baris komentar 1 berisi kondisi yang memeriksa nilai item target operasi terhadap database. Dalam contoh ini, ekspresi kondisi yang dibuat dengan metode pembantu setelah baris komentar 2 menentukan bahwa item harus dihapus dari database jika tahun akting film tidak sama dengan 2013.

[Ekspresi](ddb-en-client-expressions.md) dibahas nanti dalam panduan ini.

```
    public static void singleOperationConditionFailExample(DynamoDbEnhancedClient enhancedClient,
                                                           DynamoDbTable<ProductCatalog> catalogTable,
                                                           DynamoDbTable<MovieActor> movieActorTable) {
        try {
            enhancedClient.transactWriteItems(b -> b
                    .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId2())
                            .build())
                    .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId4ForUpdate())
                            .ignoreNulls(Boolean.TRUE).build())
                    // 1. Delete operation that contains a condition expression
                    .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder()
                            .key((Key.Builder k) -> {
                                MovieActor blanchett = getMovieActorBlanchett();
                                k.partitionValue(blanchett.getMovieName())
                                        .sortValue(blanchett.getActorName());
                            })
                            .conditionExpression(buildDeleteItemExpression())
                            .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                            .build())
                    .build());
        } catch (TransactionCanceledException ex) {
            ex.cancellationReasons().forEach(cancellationReason -> logger.info(cancellationReason.toString()));
        }
    }

    // 2. Provide condition expression to check if 'actingyear' is not equal to 2013.
    private static Expression buildDeleteItemExpression() {
        Map<String, AttributeValue> expressionValue = Map.of(
                ":year", numberValue(2013));

        return Expression.builder()
                .expression("actingyear <> :year")
                .expressionValues(expressionValue)
                .build();
    }
```

Metode pembantu berikut digunakan dalam contoh kode sebelumnya.

#### Metode pembantu
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition-helpers"></a>

```
    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }
    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Blue Jasmine");
        movieActor.setActingYear(2013);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
```

Item berikut ada di tabel setelah kode selesai berjalan.

```
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2023-03-15 11:29:07 [main] INFO  org.example.tests.TransactDemoTest:168 - MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
```

Item tetap tidak berubah dalam tabel karena transaksi gagal. `actingYear`Nilai untuk film `Blue Jasmine` adalah `2013` seperti yang ditunjukkan pada baris 2 dalam daftar item sebelum contoh kode berjalan.

Baris berikut dicatat ke konsol.

```
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Item={actor=AttributeValue(S=Cate Blanchett), movie=AttributeValue(S=Blue Jasmine), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=2013), actingschoolname=AttributeValue(S=National Institute of Dramatic Art)}, 
    Code=ConditionalCheckFailed, Message=The conditional request failed)
```

# Gunakan indeks sekunder
<a name="ddb-en-client-use-secindex"></a>

Indeks sekunder meningkatkan akses data dengan mendefinisikan kunci alternatif yang Anda gunakan dalam operasi kueri dan pemindaian. Indeks sekunder global (GSI) memiliki kunci partisi dan kunci pengurutan yang dapat berbeda dari yang ada di tabel dasar. Sebaliknya, indeks sekunder lokal (LSI) menggunakan kunci partisi dari indeks primer.

## Anotasi kelas data dengan anotasi indeks sekunder
<a name="ddb-en-client-use-secindex-annomodel"></a>

Atribut yang berpartisipasi dalam indeks sekunder memerlukan `@DynamoDbSecondarySortKey` anotasi `@DynamoDbSecondaryPartitionKey` atau anotasi.

Kelas berikut menunjukkan anotasi untuk dua indeks. GSI bernama *SubjectLastPostedDateIndex*menggunakan `Subject` atribut untuk kunci partisi dan `LastPostedDateTime` untuk kunci sortir. LSI bernama *ForumLastPostedDateIndex*menggunakan `ForumName` sebagai kunci partisi dan `LastPostedDateTime` sebagai kunci sortir.

Perhatikan bahwa `Subject` atribut tersebut memiliki peran ganda. Ini adalah kunci sortir kunci primer dan kunci partisi dari GSI bernama *SubjectLastPostedDateIndex*.

### `MessageThread` kelas
<a name="ddb-en-client-use-secindex-class"></a>

`MessageThread`Kelas ini cocok untuk digunakan sebagai kelas data untuk [tabel Thread contoh](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html) di *Amazon DynamoDB* Developer Guide.

#### Impor
<a name="ddb-en-client-use-secindex-classimports"></a>

```
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.List;
```

```
@DynamoDbBean
public class MessageThread {
    private String ForumName;
    private String Subject;
    private String Message;
    private String LastPostedBy;
    private String LastPostedDateTime;
    private Integer Views;
    private Integer Replies;
    private Integer Answered;
    private List<String> Tags;

    @DynamoDbPartitionKey
    public String getForumName() {
        return ForumName;
    }

    public void setForumName(String forumName) {
        ForumName = forumName;
    }

    // Sort key for primary index and partition key for GSI "SubjectLastPostedDateIndex".
    @DynamoDbSortKey
    @DynamoDbSecondaryPartitionKey(indexNames = "SubjectLastPostedDateIndex")
    public String getSubject() {
        return Subject;
    }

    public void setSubject(String subject) {
        Subject = subject;
    }

    // Sort key for GSI "SubjectLastPostedDateIndex" and sort key for LSI "ForumLastPostedDateIndex".
    @DynamoDbSecondarySortKey(indexNames = {"SubjectLastPostedDateIndex", "ForumLastPostedDateIndex"})
    public String getLastPostedDateTime() {
        return LastPostedDateTime;
    }

    public void setLastPostedDateTime(String lastPostedDateTime) {
        LastPostedDateTime = lastPostedDateTime;
    }
    public String getMessage() {
        return Message;
    }

    public void setMessage(String message) {
        Message = message;
    }

    public String getLastPostedBy() {
        return LastPostedBy;
    }

    public void setLastPostedBy(String lastPostedBy) {
        LastPostedBy = lastPostedBy;
    }

    public Integer getViews() {
        return Views;
    }

    public void setViews(Integer views) {
        Views = views;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "ForumRepliesIndex")
    public Integer getReplies() {
        return Replies;
    }

    public void setReplies(Integer replies) {
        Replies = replies;
    }

    public Integer getAnswered() {
        return Answered;
    }

    public void setAnswered(Integer answered) {
        Answered = answered;
    }

    public List<String> getTags() {
        return Tags;
    }

    public void setTags(List<String> tags) {
        Tags = tags;
    }

    public MessageThread() {
        this.Answered = 0;
        this.LastPostedBy = "";
        this.ForumName = "";
        this.Message = "";
        this.LastPostedDateTime = "";
        this.Replies = 0;
        this.Views = 0;
        this.Subject = "";
    }

    @Override
    public String toString() {
        return "MessageThread{" +
                "ForumName='" + ForumName + '\'' +
                ", Subject='" + Subject + '\'' +
                ", Message='" + Message + '\'' +
                ", LastPostedBy='" + LastPostedBy + '\'' +
                ", LastPostedDateTime='" + LastPostedDateTime + '\'' +
                ", Views=" + Views +
                ", Replies=" + Replies +
                ", Answered=" + Answered +
                ", Tags=" + Tags +
                '}';
    }
}
```

## Buat indeks
<a name="ddb-en-client-use-secindex-confindex"></a>

Dimulai dengan versi 2.20.86 SDK for Java, `createTable()` metode ini secara otomatis menghasilkan indeks sekunder dari anotasi kelas data. Secara default, semua atribut dari tabel dasar disalin ke indeks dan nilai throughput yang disediakan adalah 20 unit kapasitas baca dan 20 unit kapasitas tulis.

Namun, jika Anda menggunakan versi SDK sebelum 2.20.86, Anda perlu membuat indeks bersama dengan tabel seperti yang ditunjukkan pada contoh berikut. Contoh ini membangun dua indeks untuk tabel. `Thread` Parameter [builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) memiliki metode untuk mengkonfigurasi kedua jenis indeks seperti yang ditunjukkan setelah baris komentar 1 dan 2. Anda menggunakan `indexName()` metode pembuat indeks untuk mengaitkan nama indeks yang ditentukan dalam anotasi kelas data dengan jenis indeks yang dimaksud.

Kode ini mengkonfigurasi semua atribut tabel untuk berakhir di kedua indeks setelah baris komentar 3 dan 4. Informasi selengkapnya tentang [proyeksi atribut](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections) tersedia di Panduan Pengembang *Amazon DynamoDB*.

```
    public static void createMessageThreadTable(DynamoDbTable<MessageThread> messageThreadDynamoDbTable, DynamoDbClient dynamoDbClient) {
        messageThreadDynamoDbTable.createTable(b -> b
                // 1. Generate the GSI.
                .globalSecondaryIndices(gsi -> gsi.indexName("SubjectLastPostedDateIndex")
                        // 3. Populate the GSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
                // 2. Generate the LSI.
                .localSecondaryIndices(lsi -> lsi.indexName("ForumLastPostedDateIndex")
                        // 4. Populate the LSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
        );
```

## Kueri dengan menggunakan indeks
<a name="ddb-en-client-use-secindex-query"></a>

Contoh berikut query indeks *ForumLastPostedDateIndex*sekunder lokal.

Mengikuti baris komentar 2, Anda membuat [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)objek yang diperlukan saat memanggil [DynamoDbIndexmetode.query ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)). 

Anda mendapatkan referensi ke indeks yang ingin Anda kueri setelah baris komentar 3 dengan meneruskan nama indeks. Mengikuti baris komentar 4, Anda memanggil `query()` metode pada indeks yang lewat di `QueryConditional` objek. 

Anda juga mengonfigurasi kueri untuk mengembalikan tiga nilai atribut seperti yang ditunjukkan setelah baris komentar 5. Jika tidak `attributesToProject()` dipanggil, query mengembalikan semua nilai atribut. Perhatikan bahwa nama atribut yang ditentukan dimulai dengan huruf kecil. Nama atribut ini cocok dengan yang digunakan dalam tabel, belum tentu nama atribut dari kelas data.

Mengikuti baris komentar 6, ulangi hasil dan log setiap item yang dikembalikan oleh kueri dan juga menyimpannya dalam daftar untuk kembali ke pemanggil.

```
public class IndexScanExamples {
    private static Logger logger = LoggerFactory.getLogger(IndexScanExamples.class);

    public static List<MessageThread> queryUsingSecondaryIndices(String lastPostedDate,
                                                                 DynamoDbTable<MessageThread> threadTable) {
        // 1. Log the parameter value.
        logger.info("lastPostedDate value: {}", lastPostedDate);

        // 2. Create a QueryConditional whose sort key value must be greater than or equal to the parameter value.
        QueryConditional queryConditional = QueryConditional.sortGreaterThanOrEqualTo(qc ->
                qc.partitionValue("Forum02").sortValue(lastPostedDate));

        // 3. Specify the index name to query.
        final DynamoDbIndex<MessageThread> forumLastPostedDateIndex = threadTable.index("ForumLastPostedDateIndex");

        // 4. Perform the query using the QueryConditional object.
        final SdkIterable<Page<MessageThread>> pagedResult = forumLastPostedDateIndex.query(q -> q
                .queryConditional(queryConditional)
                // 5. Request three attribute in the results.
                .attributesToProject("forumName", "subject", "lastPostedDateTime"));

        List<MessageThread> collectedItems = new ArrayList<>();
        // 6. Iterate through pages response and sort the items.
        pagedResult.stream().forEach(page -> page.items().stream()
                .sorted(Comparator.comparing(MessageThread::getLastPostedDateTime))
                .forEach(mt -> {
                    // 7. Log the returned items and add the collection to return to the caller.
                    logger.info(mt.toString());
                    collectedItems.add(mt);
                }));
        return collectedItems;
    }
```

Item berikut ada dalam database sebelum query dijalankan.

```
MessageThread{ForumName='Forum01', Subject='Subject01', Message='Message01', LastPostedBy='', LastPostedDateTime='2023.03.28', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject02', Message='Message02', LastPostedBy='', LastPostedDateTime='2023.03.29', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject04', Message='Message04', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='Message08', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='Message10', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject03', Message='Message03', LastPostedBy='', LastPostedDateTime='2023.03.30', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject06', Message='Message06', LastPostedBy='', LastPostedDateTime='2023.04.02', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject09', Message='Message09', LastPostedBy='', LastPostedDateTime='2023.04.05', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum05', Subject='Subject05', Message='Message05', LastPostedBy='', LastPostedDateTime='2023.04.01', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum07', Subject='Subject07', Message='Message07', LastPostedBy='', LastPostedDateTime='2023.04.03', Views=0, Replies=0, Answered=0, Tags=null}
```

Pernyataan logging pada baris 1 dan 6 menghasilkan output konsol berikut.

```
lastPostedDate value: 2023.03.31
MessageThread{ForumName='Forum02', Subject='Subject04', Message='', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
```

*Kueri mengembalikan item dengan `forumName` nilai *Forum02* dan `lastPostedDateTime` nilai lebih besar dari atau sama dengan 2023.03.31.* Hasilnya menunjukkan `message` nilai dengan string kosong meskipun `message` atribut memiliki nilai dalam indeks. Ini karena atribut pesan tidak diproyeksikan oleh kode setelah baris komentar 5. 