

# 使用 DAX 和 AWS SDK for Java 1.x
<a name="DAX.client.java-sdk-v1"></a>

按照此过程操作，在 Amazon EC2 实例上运行用于 Amazon DynamoDB Accelerator (DAX) 的 Java 示例。

**注意**  
这些说明针对使用 AWS SDK for Java 1.x 的应用程序。对于使用 AWS SDK for Java 2.x 的应用程序，请参阅 [Java 和 DAX](DAX.client.run-application-java.md)。

**运行 DAX 的 Java 示例**

1. 安装 Java 开发工具包 (JDK)。

   ```
   sudo yum install -y java-devel
   ```

1. 下载 适用于 Java 的 AWS SDK（`.zip` 文件），然后解压缩此文件。

   ```
   wget http://sdk-for-java.amazonwebservices.com/latest/aws-java-sdk.zip
   
   unzip aws-java-sdk.zip
   ```

1. 下载最新版本的 DAX Java 客户端（`.jar` 文件）。

   ```
   wget http://dax-sdk.s3-website-us-west-2.amazonaws.com/java/DaxJavaClient-latest.jar
   ```
**注意**  
Apache Maven 提供用于 Java 的 DAX SDK 客户端。有关更多信息，请参阅 [使用客户端作为 Apache Maven 依赖项](#DAXClient.Maven)。

1. 设置 `CLASSPATH` 变量。在此例中，将 `sdkVersion` 替换为 适用于 Java 的 AWS SDK 的实际版本号（例如，`1.11.112`）。

   ```
   export SDKVERSION=sdkVersion
   
   export CLASSPATH=$(pwd)/TryDax/java:$(pwd)/DaxJavaClient-latest.jar:$(pwd)/aws-java-sdk-$SDKVERSION/lib/aws-java-sdk-$SDKVERSION.jar:$(pwd)/aws-java-sdk-$SDKVERSION/third-party/lib/*
   ```

1. 下载示例程序源代码（`.zip` 文件）。

   ```
   wget http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/samples/TryDax.zip
   ```

   下载完成后，解压缩源文件。

   ```
   unzip TryDax.zip
   ```

1. 导航到 Java 代码目录并按如下方式编译代码。

   ```
   cd TryDax/java/
   javac TryDax*.java
   ```

1. 运行程序。

   ```
   java TryDax
   ```

   您应该可以看到类似于如下所示的输出内容。

   ```
   Creating a DynamoDB client
   
   Attempting to create table; please wait...
   Successfully created table.  Table status: ACTIVE
   Writing data to the table...
   Writing 10 items for partition key: 1
   Writing 10 items for partition key: 2
   Writing 10 items for partition key: 3
   Writing 10 items for partition key: 4
   Writing 10 items for partition key: 5
   Writing 10 items for partition key: 6
   Writing 10 items for partition key: 7
   Writing 10 items for partition key: 8
   Writing 10 items for partition key: 9
   Writing 10 items for partition key: 10
   
   Running GetItem, Scan, and Query tests...
   First iteration of each test will result in cache misses
   Next iterations are cache hits
   
   GetItem test - partition key 1 and sort keys 1-10
   	Total time: 136.681 ms - Avg time: 13.668 ms
   	Total time: 122.632 ms - Avg time: 12.263 ms
   	Total time: 167.762 ms - Avg time: 16.776 ms
   	Total time: 108.130 ms - Avg time: 10.813 ms
   	Total time: 137.890 ms - Avg time: 13.789 ms
   Query test - partition key 5 and sort keys between 2 and 9
   	Total time: 13.560 ms - Avg time: 2.712 ms
   	Total time: 11.339 ms - Avg time: 2.268 ms
   	Total time: 7.809 ms - Avg time: 1.562 ms
   	Total time: 10.736 ms - Avg time: 2.147 ms
   	Total time: 12.122 ms - Avg time: 2.424 ms
   Scan test - all items in the table
   	Total time: 58.952 ms - Avg time: 11.790 ms
   	Total time: 25.507 ms - Avg time: 5.101 ms
   	Total time: 37.660 ms - Avg time: 7.532 ms
   	Total time: 26.781 ms - Avg time: 5.356 ms
   	Total time: 46.076 ms - Avg time: 9.215 ms
   
   Attempting to delete table; please wait...
   Successfully deleted table.
   ```

   记下计时信息—`GetItem`、`Query` 和 `Scan` 测试所需的时间（以毫秒为单位）。

1. 在上一步中，针对 DynamoDB 端点运行程序。现在再次运行程序，这次 `GetItem`、`Query` 和 `Scan` 操作由 DAX 集群处理。

   要确定 DAX 集群的端点，请选择下列选项之一：
   + **使用 DynamoDB 控制台** — 选择 DAX 集群。集群端点显示在控制台中，如下面的示例所示。

     ```
     dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com
     ```
   + **使用 AWS CLI** — 输入下面的命令。

     ```
     aws dax describe-clusters --query "Clusters[*].ClusterDiscoveryEndpoint"
     ```

     集群端点显示在输出中，如下面的示例所示。

     ```
     {
         "Address": "my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com",
         "Port": 8111,
         "URL": "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
     }
     ```

   现在再次运行程序，这次指定集群端点作为命令行参数。

   ```
   java TryDax dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com
   ```

   查看输出的其余内容，并记下计时信息。与使用 DynamoDB 相比，使用 DAX 时，`GetItem`、`Query` 和 `Scan` 的运行时间应明显更短。

有关此程序的更多信息，请参加以下章节：
+ [TryDax.java](DAX.client.run-application-java.TryDax.md)
+ [TryDaxHelper.java](DAX.client.run-application-java.TryDaxHelper.md)
+ [TryDaxTests.java](DAX.client.run-application-java.TryDaxTests.md)

## 使用客户端作为 Apache Maven 依赖项
<a name="DAXClient.Maven"></a>

按照以下步骤，在应用程序中将 DAX SDK for Java 客户端用作依赖项。

**将客户端用作 Maven 依赖项**

1. 下载并安装 Apache Maven。有关更多信息，请参见[下载 Apache Maven](https://maven.apache.org/download.cgi) 和[安装 Apache Maven](https://maven.apache.org/install.html)。

1. 将客户端 Maven 依赖项添加到应用程序的项目对象模型 (POM) 文件。在此示例中，将 `x.x.x.x` 替换为客户端实际版本号（例如 `1.0.200704.0`）。

   ```
   <!--Dependency:-->
   <dependencies>
       <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>amazon-dax-client</artifactId>
        <version>x.x.x.x</version>
       </dependency>
   </dependencies>
   ```

# TryDax.java
<a name="DAX.client.run-application-java.TryDax"></a>

`TryDax.java` 文件包含 `main` 方法。如果在没有命令行参数的情况下运行程序，将创建一个 Amazon DynamoDB 客户端，并将该客户端用于所有 API 操作。如果在命令行中指定一个 DynamoDB Accelerator (DAX) 集群端点，程序还将创建一个 DAX 客户端，并用于 `GetItem`、`Query` 和 `Scan` 操作。

可以通过多种方式修改程序：
+ 使用 DAX 客户端而不是 DynamoDB 客户端。有关更多信息，请参阅 [Java 和 DAX](DAX.client.run-application-java.md)。
+ 为测试表选择其他名称。
+ 通过更改 `helper.writeData` 参数修改写入的项目数。第二个参数是分区键数，第三个参数是排序键数。默认情况下，程序使用 1–10 作为分区键值，使用 1–10 作为排序键值，总共向表写入 100 个项目。有关更多信息，请参阅 [TryDaxHelper.java](DAX.client.run-application-java.TryDaxHelper.md)。
+ 修改 `GetItem`、`Query` 和 `Scan` 测试的数量及其参数。
+ 注释掉包含 `helper.createTable` 和 `helper.deleteTable` 的行（如果不希望每次运行程序时都创建和删除表）。

**注意**  
要运行此程序，您可以设置 Maven 将 DAX SDK for Java 客户端和 适用于 Java 的 AWS SDK 作为依赖项。有关更多信息，请参阅 [使用客户端作为 Apache Maven 依赖项](DAX.client.java-sdk-v1.md#DAXClient.Maven)。  
或者可以下载 DAX Java 客户端和 适用于 Java 的 AWS SDK 并加入类路径。有关设置 [Java 和 DAX](DAX.client.run-application-java.md) 变量的示例，请参阅 `CLASSPATH`。

```
public class TryDax {

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

        TryDaxHelper helper = new TryDaxHelper();
        TryDaxTests tests = new TryDaxTests();

        DynamoDB ddbClient = helper.getDynamoDBClient();
        DynamoDB daxClient = null;
        if (args.length >= 1) {
            daxClient = helper.getDaxClient(args[0]);
        }

        String tableName = "TryDaxTable";

        System.out.println("Creating table...");
        helper.createTable(tableName, ddbClient);
        System.out.println("Populating table...");
        helper.writeData(tableName, ddbClient, 10, 10);

        DynamoDB testClient = null;
        if (daxClient != null) {
            testClient = daxClient;
        } else {
            testClient = ddbClient;
        }

        System.out.println("Running GetItem, Scan, and Query tests...");
        System.out.println("First iteration of each test will result in cache misses");
        System.out.println("Next iterations are cache hits\n");

        // GetItem
        tests.getItemTest(tableName, testClient, 1, 10, 5);

        // Query
        tests.queryTest(tableName, testClient, 5, 2, 9, 5);

        // Scan
        tests.scanTest(tableName, testClient, 5);

        helper.deleteTable(tableName, ddbClient);
    }

}
```

# TryDaxHelper.java
<a name="DAX.client.run-application-java.TryDaxHelper"></a>

`TryDaxHelper.java` 文件包含一些实用程序方法。

`getDynamoDBClient` 和 `getDaxClient` 方法提供 Amazon DynamoDB 和 DynamoDB Accelerator (DAX) 客户端。为了实现控制层面操作（`CreateTable`、`DeleteTable`）和写入操作，程序使用 DynamoDB 客户端。如果指定 DAX 集群端点，则主程序将创建一个 DAX 客户端，用于执行读取操作（`GetItem`、`Query`、`Scan`）。

其他 `TryDaxHelper` 方法（`createTable`、`writeData`、`deleteTable`）用于设置和停用 DynamoDB 表及其数据。

可以通过多种方式修改程序：
+ 对表使用不同的预置吞吐量设置。
+ 修改写入的每个项目的大小（参见 `writeData` 方法的 `stringSize` 变量)。
+ 修改 `GetItem`、`Query` 和 `Scan` 测试的数量及其参数。
+ 注释掉包含 `helper.CreateTable` 和 `helper.DeleteTable` 的行（如果不希望每次运行程序时都创建和删除表）。

**注意**  
 要运行此程序，您可以设置 Maven 将 DAX SDK for Java 客户端和 适用于 Java 的 AWS SDK 作为依赖项。有关更多信息，请参阅 [使用客户端作为 Apache Maven 依赖项](DAX.client.java-sdk-v1.md#DAXClient.Maven)。  
或者可以下载 DAX Java 客户端和 适用于 Java 的 AWS SDK 并加入类路径。有关设置 [Java 和 DAX](DAX.client.run-application-java.md) 变量的示例，请参阅 `CLASSPATH`。

```
import com.amazon.dax.client.dynamodbv2.AmazonDaxClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.util.EC2MetadataUtils;

public class TryDaxHelper {

    private static final String region = EC2MetadataUtils.getEC2InstanceRegion();

    DynamoDB getDynamoDBClient() {
        System.out.println("Creating a DynamoDB client");
        AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
                .withRegion(region)
                .build();
        return new DynamoDB(client);
    }

    DynamoDB getDaxClient(String daxEndpoint) {
        System.out.println("Creating a DAX client with cluster endpoint " + daxEndpoint);
        AmazonDaxClientBuilder daxClientBuilder = AmazonDaxClientBuilder.standard();
        daxClientBuilder.withRegion(region).withEndpointConfiguration(daxEndpoint);
        AmazonDynamoDB client = daxClientBuilder.build();
        return new DynamoDB(client);
    }

    void createTable(String tableName, DynamoDB client) {
        Table table = client.getTable(tableName);
        try {
            System.out.println("Attempting to create table; please wait...");

            table = client.createTable(tableName,
                    Arrays.asList(
                            new KeySchemaElement("pk", KeyType.HASH), // Partition key
                            new KeySchemaElement("sk", KeyType.RANGE)), // Sort key
                    Arrays.asList(
                            new AttributeDefinition("pk", ScalarAttributeType.N),
                            new AttributeDefinition("sk", ScalarAttributeType.N)),
                    new ProvisionedThroughput(10L, 10L));
            table.waitForActive();
            System.out.println("Successfully created table.  Table status: " +
                    table.getDescription().getTableStatus());

        } catch (Exception e) {
            System.err.println("Unable to create table: ");
            e.printStackTrace();
        }
    }

    void writeData(String tableName, DynamoDB client, int pkmax, int skmax) {
        Table table = client.getTable(tableName);
        System.out.println("Writing data to the table...");

        int stringSize = 1000;
        StringBuilder sb = new StringBuilder(stringSize);
        for (int i = 0; i < stringSize; i++) {
            sb.append('X');
        }
        String someData = sb.toString();

        try {
            for (Integer ipk = 1; ipk <= pkmax; ipk++) {
                System.out.println(("Writing " + skmax + " items for partition key: " + ipk));
                for (Integer isk = 1; isk <= skmax; isk++) {
                    table.putItem(new Item()
                            .withPrimaryKey("pk", ipk, "sk", isk)
                            .withString("someData", someData));
                }
            }
        } catch (Exception e) {
            System.err.println("Unable to write item:");
            e.printStackTrace();
        }
    }

    void deleteTable(String tableName, DynamoDB client) {
        Table table = client.getTable(tableName);
        try {
            System.out.println("\nAttempting to delete table; please wait...");
            table.delete();
            table.waitForDelete();
            System.out.println("Successfully deleted table.");

        } catch (Exception e) {
            System.err.println("Unable to delete table: ");
            e.printStackTrace();
        }
    }

}
```

# TryDaxTests.java
<a name="DAX.client.run-application-java.TryDaxTests"></a>

`TryDaxTests.java` 文件包含对 Amazon DynamoDB 中的测试表执行读取操作的方法。这些方法不考虑访问数据的方式（使用 DynamoDB 客户端还是 DAX 客户端），因此无需修改应用程序逻辑。

可以通过多种方式修改程序：
+ 修改 `queryTest` 方法，使其使用其他 `KeyConditionExpression`。
+ 将 `ScanFilter` 添加到 `scanTest` 方法，这样仅返回部分项目。

**注意**  
 要运行此程序，您可以设置 Maven 将 DAX SDK for Java 客户端和 适用于 Java 的 AWS SDK 作为依赖项。有关更多信息，请参阅 [使用客户端作为 Apache Maven 依赖项](DAX.client.java-sdk-v1.md#DAXClient.Maven)。  
或者可以下载 DAX Java 客户端和 适用于 Java 的 AWS SDK 并加入类路径。有关设置 [Java 和 DAX](DAX.client.run-application-java.md) 变量的示例，请参阅 `CLASSPATH`。

```
import java.util.Iterator;

import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.ScanOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;

public class TryDaxTests {

    void getItemTest(String tableName, DynamoDB client, int pk, int sk, int iterations) {
        long startTime, endTime;
        System.out.println("GetItem test - partition key " + pk + " and sort keys 1-" + sk);
        Table table = client.getTable(tableName);

        for (int i = 0; i < iterations; i++) {
            startTime = System.nanoTime();
            try {
                for (Integer ipk = 1; ipk <= pk; ipk++) {
                    for (Integer isk = 1; isk <= sk; isk++) {
                        table.getItem("pk", ipk, "sk", isk);
                    }
                }
            } catch (Exception e) {
                System.err.println("Unable to get item:");
                e.printStackTrace();
            }
            endTime = System.nanoTime();
            printTime(startTime, endTime, pk * sk);
        }
    }

    void queryTest(String tableName, DynamoDB client, int pk, int sk1, int sk2, int iterations) {
        long startTime, endTime;
        System.out.println("Query test - partition key " + pk + " and sort keys between " + sk1 + " and " + sk2);
        Table table = client.getTable(tableName);

        HashMap<String, Object> valueMap = new HashMap<String, Object>();
        valueMap.put(":pkval", pk);
        valueMap.put(":skval1", sk1);
        valueMap.put(":skval2", sk2);

        QuerySpec spec = new QuerySpec()
                .withKeyConditionExpression("pk = :pkval and sk between :skval1 and :skval2")
                .withValueMap(valueMap);

        for (int i = 0; i < iterations; i++) {
            startTime = System.nanoTime();
            ItemCollection<QueryOutcome> items = table.query(spec);

            try {
                Iterator<Item> iter = items.iterator();
                while (iter.hasNext()) {
                    iter.next();
                }
            } catch (Exception e) {
                System.err.println("Unable to query table:");
                e.printStackTrace();
            }
            endTime = System.nanoTime();
            printTime(startTime, endTime, iterations);
        }
    }

    void scanTest(String tableName, DynamoDB client, int iterations) {
        long startTime, endTime;
        System.out.println("Scan test - all items in the table");
        Table table = client.getTable(tableName);

        for (int i = 0; i < iterations; i++) {
            startTime = System.nanoTime();
            ItemCollection<ScanOutcome> items = table.scan();
            try {

                Iterator<Item> iter = items.iterator();
                while (iter.hasNext()) {
                    iter.next();
                }
            } catch (Exception e) {
                System.err.println("Unable to scan table:");
                e.printStackTrace();
            }
            endTime = System.nanoTime();
            printTime(startTime, endTime, iterations);
        }
    }

    public void printTime(long startTime, long endTime, int iterations) {
        System.out.format("\tTotal time: %.3f ms - ", (endTime - startTime) / (1000000.0));
        System.out.format("Avg time: %.3f ms\n", (endTime - startTime) / (iterations * 1000000.0));
    }
}
```