

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 适用于 Java 的 Amazon QLDB 驱动程序
<a name="getting-started.java"></a>

**重要**  
终止支持通知：现有客户将能够使用 Amazon QLDB，直到 2025 年 7 月 31 日终止支持。有关更多详细信息，请参阅[将亚马逊 QLDB 账本迁移到亚马逊 Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

要处理账本中的数据，您可以使用提供的驱动程序从 Java 应用程序连接到 Amazon QLDB。 AWS 以下主题介绍了如何开始使用 Java 上 QLDB 驱动程序。

**Topics**
+ [驱动程序资源](#getting-started.java.resources)
+ [先决条件](#getting-started.java.prereqs)
+ [设置您的默认 AWS 凭证和区域](#getting-started.java.credentials)
+ [安装](#getting-started.java.install)
+ [快速入门教程](driver-quickstart-java.md)
+ [说明书参考](driver-cookbook-java.md)

## 驱动程序资源
<a name="getting-started.java.resources"></a>

有关 Java 驱动程序支持功能的更多信息，请参阅以下资源：
+ API 参考：[2.x](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/), [1.x](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/1.1.0/index.html)
+ [驱动程序源代码 (GitHub)](https://github.com/awslabs/amazon-qldb-driver-java)
+ [示例应用程序源代码 (GitHub)](https://github.com/aws-samples/amazon-qldb-dmv-sample-java)
+ [账本加载器框架 (GitHub)](https://github.com/awslabs/amazon-qldb-ledger-load-java)
+ [Amazon Ion 代码示例](ion.code-examples.md)

## 先决条件
<a name="getting-started.java.prereqs"></a>

开始使用适用于 Java 的 QLDB 驱动程序之前，您必须执行以下操作:

1. 按照中的 AWS 设置说明进行操作[访问 Amazon QLDB](accessing.md)。这包括以下这些：

   1. 报名参加 AWS.

   1. 创建具有适当 QLDB 权限的用户。

   1. 授权以编程方式访问开发。

1. 通过下载并安装以下内容来设置一个 Java 开发环境：

   1. Java SE Development Kit 8，例如 [Amazon Corretto](https://docs.aws.amazon.com/corretto/latest/corretto-8-ug/downloads-list.html) 8。

   1. （可选）您选择的 Java 集成式开发环境（IDE），例如 [Eclipse](http://www.eclipse.org) 或 [IntelliJ](https://www.jetbrains.com/idea/)。

1. 为 b 适用于 Java 的 AWS SDK y 配置您的开发环境[设置您的默认 AWS 凭证和区域](#getting-started.java.credentials)。

接下来，您可下载完整的教程示例应用程序，也可以只在 Java 项目中安装驱动程序并运行短代码示例。
+ 要在现有项目中安装 QLDB 驱动程序和 适用于 Java 的 AWS SDK ，请继续。[安装](#getting-started.java.install)
+ 要设置项目并运行演示分类账上基本数据事务的简短代码示例，请参阅 [快速入门教程](driver-quickstart-java.md)。
+ 要在完整的教程示例应用程序中运行更深入的数据和管理 API 操作示例，请参阅 [Java 教程](getting-started.java.tutorial.md)。

## 设置您的默认 AWS 凭证和区域
<a name="getting-started.java.credentials"></a>

QLDB 驱动程序和[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java)底层要求您在运行时 AWS 向应用程序提供凭证。本指南中的代码示例假设您使用 AWS 凭证文件，如 *AWS SDK for Java 2.x 《开发者指南》* 中的 [设置默认凭证和区域](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-credentials) 所述。

作为这些步骤的一部分，您还应设置默认值 AWS 区域 以确定默认 QLDB 终端节点。在默认的 AWS 区域中，代码示例连接到 QLDB。有关 QLDB 区域的完整列表，请参阅AWS 一般参考**中的 [Amazon QLDB 端点和限额](https://docs.aws.amazon.com/general/latest/gr/qldb.html)。

以下是名为的 AWS 凭据文件的示例`~/.aws/credentials`，其中波浪号字符 (`~`) 表示您的主目录。

```
[default] 
aws_access_key_id = your_access_key_id
aws_secret_access_key = your_secret_access_key
```

用您自己的 AWS 凭证值代替值*your\$1access\$1key\$1id*和*your\$1secret\$1access\$1key*。

## 安装
<a name="getting-started.java.install"></a>

QLDB 支持以下 Java 驱动程序版本及 AWS 其 SDK 依赖关系。


****  

| 驱动程序版本 | AWS SDK | 状态 | 最新发布日期 | 
| --- | --- | --- | --- | 
| [1.x](https://search.maven.org/artifact/software.amazon.qldb/amazon-qldb-driver-java/1.1.0/jar) | 适用于 Java 的 AWS SDK 1.x | 量产版 | 2020 年 3 月 20 日 | 
| [2.x](https://search.maven.org/artifact/software.amazon.qldb/amazon-qldb-driver-java/2.3.1/jar) | AWS SDK for Java 2.x | 量产版 | 2021 年 6 月 4 日 | 

要安装 QLDB 驱动程序，我们建议使用依赖项管理系统，比如 Gradle 或 Maven。例如，将以下构件作为依赖项添加到您的 Java 项目中。

------
#### [ 2.x ]

**Gradle**

在您的 `build.gradle` 配置文件中添加此依赖项。

```
dependencies {
    compile group: 'software.amazon.qldb', name: 'amazon-qldb-driver-java', version: '2.3.1'
}
```

**Maven**

在您的 `pom.xml` 配置文件中添加此依赖项。

```
<dependencies>
  <dependency>
    <groupId>software.amazon.qldb</groupId>
    <artifactId>amazon-qldb-driver-java</artifactId>
    <version>2.3.1</version>
  </dependency>
</dependencies>
```

此工件自动包含 AWS SDK for Java 2.x 核心模块、[Amazon Ion](ion.md) 库和其他必需的依赖项。

------
#### [ 1.x ]

**Gradle**

在您的 `build.gradle` 配置文件中添加此依赖项。

```
dependencies {
    compile group: 'software.amazon.qldb', name: 'amazon-qldb-driver-java', version: '1.1.0'
}
```

**Maven**

在您的 `pom.xml` 配置文件中添加此依赖项。

```
<dependencies>
  <dependency>
    <groupId>software.amazon.qldb</groupId>
    <artifactId>amazon-qldb-driver-java</artifactId>
    <version>1.1.0</version>
  </dependency>
</dependencies>
```

此工件自动包含 适用于 Java 的 AWS SDK 核心模块、[Amazon Ion](ion.md) 库和其他必需的依赖项。

**重要**  
**Amazon Ion 命名空间** - 在应用程序中导入 Amazon Ion 类时，必须使用命名空间 `com.amazon.ion` 下的软件包。 适用于 Java 的 AWS SDK 依赖于`software.amazon.ion`命名空间下的另一个 Ion 包，但这是一个与 QLDB 驱动程序不兼容的旧包。

------

有关如何在分类账上运行基本数据事务的简短代码示例，请参阅 [说明书参考](driver-cookbook-java.md)。

### 其他可选库
<a name="getting-started.java.install-optional"></a>

另外，您还可以在项目中添加以下有用的库。这些构件是 [Java 教程](getting-started.java.tutorial.md) 示例应用程序中必需的依赖项。

1. [aws-java-sdk-qldb](https://search.maven.org/artifact/com.amazonaws/aws-java-sdk-qldb/1.11.785/jar)— 的 QLDB 模块。 适用于 Java 的 AWS SDK QLDB 支持的最低版本为 `1.11.785`。

   在您的应用程序中使用此模块可以直接与 [Amazon QLDB API 参考](api-reference.md) 中列出的管理 API 操作进行交互。

1. [jackson-dataformat-ion](https://search.maven.org/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-ion/2.10.0/bundle)— FasterXML 的 Jackson 数据格式模块，适用于 Ion。示例应用程序需要版本 `2.10.0` 或更高版本。

------
#### [ Gradle ]

将这些依赖项添加到您的 `build.gradle` 配置文件中。

```
dependencies {
    compile group: 'com.amazonaws', name: 'aws-java-sdk-qldb', version: '1.11.785'
    compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-ion', version: '2.10.0'
}
```

------
#### [ Maven ]

将这些依赖项添加到您的 `pom.xml` 配置文件中。

```
<dependencies>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-qldb</artifactId>
    <version>1.11.785</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-ion</artifactId>
    <version>2.10.0</version>
  </dependency>
</dependencies>
```

------

# 适用于 Java 的 Amazon QLDB 驱动程序 — 快速入门教程
<a name="driver-quickstart-java"></a>

**重要**  
终止支持通知：现有客户将能够使用 Amazon QLDB，直到 2025 年 7 月 31 日终止支持。有关更多详细信息，请参阅[将亚马逊 QLDB 账本迁移到亚马逊 Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

在本教程中，您将学习如何使用适用于 Java 的最新版 Amazon QLDB 驱动程序来设置简单应用程序。本指南包括安装驱动程序的步骤以及*创建、读取、更新和删除*（CRUD）的基本操作的简短代码示例。有关在完整示例应用程序中演示这些操作的更深入的示例，请参阅 [Java 教程](getting-started.java.tutorial.md)。

**Topics**
+ [先决条件](#driver-quickstart-java.prereqs)
+ [步骤 1：设置您的项目](#driver-quickstart-java.step-1)
+ [第 2 步：初始化驱动程序](#driver-quickstart-java.step-2)
+ [第 3 步：创建表和索引](#driver-quickstart-java.step-3)
+ [第 4 步：插入文档](#driver-quickstart-java.step-4)
+ [第 5 步：查询文档](#driver-quickstart-java.step-5)
+ [第 6 步：更新文档](#driver-quickstart-java.step-6)
+ [运行完整的应用程序](#driver-quickstart-java.complete)

## 先决条件
<a name="driver-quickstart-java.prereqs"></a>

在开始之前，请务必执行以下操作：

1. 请为 Java 驱动程序完成（[先决条件](getting-started.java.md#getting-started.java.prereqs)如果尚未执行此操作）。这包括注册 AWS、授予开发所需的编程访问权限以及安装 Java 集成开发环境 (IDE)。

1. 创建一个名为 `quick-start` 分类账。

   要了解如何创建分类账，请参阅*控制台入门*中的 [Amazon QLDB 分类账的基本操作](ledger-management.basics.md) 或 [第 1 步：创建新分类账](getting-started-step-1.md)。

## 步骤 1：设置您的项目
<a name="driver-quickstart-java.step-1"></a>

首先，您需要设置您的 Java 项目。我们建议在本教程中使用 [Maven](https://maven.apache.org/index.html) 依赖项管理系统。

**注意**  
如果您使用的 IDE 具有自动执行这些设置步骤的功能，则可以直接跳到 [第 2 步：初始化驱动程序](#driver-quickstart-java.step-2)。

1. 为应用程序创建一个文件夹。

   ```
   $ mkdir myproject
   $ cd myproject
   ```

1. 输入以下命令从 Maven 模板初始化项目。根据*project-package*需要*project-name**maven-template*用您自己的值替换、和。

   ```
   $ mvn archetype:generate
     -DgroupId=project-package \
     -DartifactId=project-name \
     -DarchetypeArtifactId=maven-template \
     -DinteractiveMode=false
   ```

   对于*maven-template*，你可以使用基本的 Maven 模板：`maven-archetype-quickstart`

1. 要将[ Java 的 QLDB 驱动程序](https://search.maven.org/artifact/software.amazon.qldb/amazon-qldb-driver-java/2.3.1/jar)添加为项目依赖项，请导航到新创建的 `pom.xml` 文件并添加以下构件。

   ```
   <dependency>
       <groupId>software.amazon.qldb</groupId>
       <artifactId>amazon-qldb-driver-java</artifactId>
       <version>2.3.1</version>
   </dependency>
   ```

   此构件自动包含 [AWS SDK for Java 2.x](https://aws.amazon.com/sdk-for-java) 核心模块、[Amazon Ion](ion.md) 库和其他必需的依赖项。您的 `pom.xml` 文件应类似于如下所示：

   ```
   <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>software.amazon.qldb</groupId>
     <artifactId>qldb-quickstart</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>qldb-quickstart</name>
     <url>http://maven.apache.org</url>
     <dependencies>
       <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>3.8.1</version>
         <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>software.amazon.qldb</groupId>
           <artifactId>amazon-qldb-driver-java</artifactId>
           <version>2.3.1</version>
       </dependency>
     </dependencies>
   </project>
   ```

1. 打开 `App.java`文件。

   然后，按以下步骤中逐步添加代码示例，尝试一些基本的 CRUD 操作。或者，您可以跳过本 step-by-step教程，改为运行[完整的应用程序](#driver-quickstart-java.complete)。

## 第 2 步：初始化驱动程序
<a name="driver-quickstart-java.step-2"></a>

初始化连接到名为 `quick-start` 的分类账的驱动程序实例。将以下代码添加到您的 `App.java`文件。

```
import java.util.*;
import com.amazon.ion.*;
import com.amazon.ion.system.*;
import software.amazon.awssdk.services.qldbsession.QldbSessionClient;
import software.amazon.qldb.*;

public final class App {
    public static IonSystem ionSys = IonSystemBuilder.standard().build();
    public static QldbDriver qldbDriver;

    public static void main(final String... args) {
        System.out.println("Initializing the driver");
        qldbDriver = QldbDriver.builder()
            .ledger("quick-start")
            .transactionRetryPolicy(RetryPolicy
                .builder()
                .maxRetries(3)
                .build())
            .sessionClientBuilder(QldbSessionClient.builder())
            .build();
    }
}
```

## 第 3 步：创建表和索引
<a name="driver-quickstart-java.step-3"></a>

以下代码示例显示如何运行 `CREATE TABLE` 和 `CREATE INDEX`。

在 `main` 方法中，添加以下代码，创建名为 `People` 的表以及该表上的 `lastName` 字段的索引。[索引](ql-reference.create-index.md)是优化查询性能和帮助限制[乐观并发控制（OCC）冲突异常](concurrency.md)所必需的。

```
// Create a table and an index in the same transaction
qldbDriver.execute(txn -> {
    System.out.println("Creating a table and an index");
    txn.execute("CREATE TABLE People");
    txn.execute("CREATE INDEX ON People(lastName)");
});
```

## 第 4 步：插入文档
<a name="driver-quickstart-java.step-4"></a>

以下代码示例显示如何运行 `INSERT` 语句。QLDB 支持 [PartiQL](ql-reference.md) 查询语言（兼容 SQL）和 [Amazon Ion](ion.md) 数据格式（JSON 的超集）。

添加以下代码，在 `People` 表格中插入文档。

```
// Insert a document
qldbDriver.execute(txn -> {
    System.out.println("Inserting a document");
    IonStruct person = ionSys.newEmptyStruct();
    person.put("firstName").newString("John");
    person.put("lastName").newString("Doe");
    person.put("age").newInt(32);
    txn.execute("INSERT INTO People ?", person);
});
```

此示例使用问号（`?`）作为变量占位符，将文档信息传递给语句。使用占位符时，必须传递一个 `IonValue` 类型的值。

**提示**  
要使用单个[INSERT](ql-reference.insert.md)语句插入多个文档，可以向该语句传递一个类型的参数 [IonList](driver-working-with-ion.md#driver-ion-list)（显式转换为`IonValue`），如下所示。  

```
// people is an IonList explicitly cast as an IonValue
txn.execute("INSERT INTO People ?", (IonValue) people);
```
传递 `IonList` 列表时，不要将变量占位符（`?`）包括在双尖括号（ `<<...>>` ）内。在手动 PartiQL 语句中，双尖括号表示名为*bag*的无序集合。

## 第 5 步：查询文档
<a name="driver-quickstart-java.step-5"></a>

以下代码示例显示如何运行 `SELECT` 语句。

添加以下代码，用于从 `People` 表格中查询文档。

```
// Query the document
qldbDriver.execute(txn -> {
    System.out.println("Querying the table");
    Result result = txn.execute("SELECT * FROM People WHERE lastName = ?",
            ionSys.newString("Doe"));
    IonStruct person = (IonStruct) result.iterator().next();
    System.out.println(person.get("firstName")); // prints John
    System.out.println(person.get("lastName")); // prints Doe
    System.out.println(person.get("age")); // prints 32
});
```

## 第 6 步：更新文档
<a name="driver-quickstart-java.step-6"></a>

以下代码示例显示如何运行 `UPDATE` 语句。

1. 添加以下代码，通过更新 `age` 到 `42` 来更新 `People` 表中的文档。

   ```
   // Update the document
   qldbDriver.execute(txn -> {
       System.out.println("Updating the document");
       final List<IonValue> parameters = new ArrayList<>();
       parameters.add(ionSys.newInt(42));
       parameters.add(ionSys.newString("Doe"));
       txn.execute("UPDATE People SET age = ? WHERE lastName = ?", parameters);
   });
   ```

1. 再次查询文档以查看更新的值。

   ```
   // Query the updated document
   qldbDriver.execute(txn -> {
       System.out.println("Querying the table for the updated document");
       Result result = txn.execute("SELECT * FROM People WHERE lastName = ?",
               ionSys.newString("Doe"));
       IonStruct person = (IonStruct) result.iterator().next();
       System.out.println(person.get("firstName")); // prints John
       System.out.println(person.get("lastName")); // prints Doe
       System.out.println(person.get("age")); // prints 32
   });
   ```

1. 使用 Maven 或你的 IDE 来编译和运行该 `App.java` 文件。

## 运行完整的应用程序
<a name="driver-quickstart-java.complete"></a>

以下代码示例是 `App.java` 应用程序的完整版本。您还可以从头到尾复制并运行此代码示例，而不必单独执行前面的步骤。此应用程序演示了对名为 `quick-start` 的分类账的一些基本的 CRUD 操作。

**注意**  
在运行此代码之前，请确保 `quick-start` 分类账中还没有名为 `People` 的活动表。  
在第一行，替换为中*project-package*用于 Maven 命令的`groupId`[步骤 1：设置您的项目](#driver-quickstart-java.step-1)值。

```
package project-package;

import java.util.*;
import com.amazon.ion.*;
import com.amazon.ion.system.*;
import software.amazon.awssdk.services.qldbsession.QldbSessionClient;
import software.amazon.qldb.*;

public class App {
    public static IonSystem ionSys = IonSystemBuilder.standard().build();
    public static QldbDriver qldbDriver;

    public static void main(final String... args) {
        System.out.println("Initializing the driver");
        qldbDriver = QldbDriver.builder()
            .ledger("quick-start")
            .transactionRetryPolicy(RetryPolicy
                .builder()
                .maxRetries(3)
                .build())
            .sessionClientBuilder(QldbSessionClient.builder())
            .build();

        // Create a table and an index in the same transaction
        qldbDriver.execute(txn -> {
            System.out.println("Creating a table and an index");
            txn.execute("CREATE TABLE People");
            txn.execute("CREATE INDEX ON People(lastName)");
        });
        
        // Insert a document
        qldbDriver.execute(txn -> {
            System.out.println("Inserting a document");
            IonStruct person = ionSys.newEmptyStruct();
            person.put("firstName").newString("John");
            person.put("lastName").newString("Doe");
            person.put("age").newInt(32);
            txn.execute("INSERT INTO People ?", person);
        });
        
        // Query the document
        qldbDriver.execute(txn -> {
            System.out.println("Querying the table");
            Result result = txn.execute("SELECT * FROM People WHERE lastName = ?",
                    ionSys.newString("Doe"));
            IonStruct person = (IonStruct) result.iterator().next();
            System.out.println(person.get("firstName")); // prints John
            System.out.println(person.get("lastName")); // prints Doe
            System.out.println(person.get("age")); // prints 32
        });
        
        // Update the document
        qldbDriver.execute(txn -> {
            System.out.println("Updating the document");
            final List<IonValue> parameters = new ArrayList<>();
            parameters.add(ionSys.newInt(42));
            parameters.add(ionSys.newString("Doe"));
            txn.execute("UPDATE People SET age = ? WHERE lastName = ?", parameters);
        });
        
        // Query the updated document
        qldbDriver.execute(txn -> {
            System.out.println("Querying the table for the updated document");
            Result result = txn.execute("SELECT * FROM People WHERE lastName = ?",
                    ionSys.newString("Doe"));
            IonStruct person = (IonStruct) result.iterator().next();
            System.out.println(person.get("firstName")); // prints John
            System.out.println(person.get("lastName")); // prints Doe
            System.out.println(person.get("age")); // prints 42
        });
    }
}
```

使用 Maven 或你的 IDE 来编译和运行该 `App.java` 文件。

# Java 的 Amazon QLDB 驱动程序 — 说明书参考
<a name="driver-cookbook-java"></a>

**重要**  
终止支持通知：现有客户将能够使用 Amazon QLDB，直到 2025 年 7 月 31 日终止支持。有关更多详细信息，请参阅[将亚马逊 QLDB 账本迁移到亚马逊 Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

本参考指南展示了 Java 的 Amazon QLDB 驱动程序的常见用例。它提供了 Java 代码示例，演示了如何使用该驱动程序运行基本的*创建、读取、更新和删除*（CRUD）操作。它还包括用于处理 Amazon Ion 数据的代码示例。此外，本指南还重点介绍了使事务具有幂等性和实现唯一性约束的最佳实践。

**注意**  
在适用的情况下，某些用例对于 Java 的 QLDB 驱动程序的每个支持主要版本都配备不同代码示例。

**Contents**
+ [导入驱动程序](#cookbook-java.importing)
+ [实例化驱动程序](#cookbook-java.instantiating)
+ [CRUD 操作](#cookbook-java.crud)
  + [创建表](#cookbook-java.crud.creating-tables)
  + [创建索引](#cookbook-java.crud.creating-indexes)
  + [阅读文档](#cookbook-java.crud.reading)
  + [插入文档](#cookbook-java.crud.inserting)
    + [在一条语句内插入多个文档](#cookbook-java.crud.inserting.multiple)
  + [更新文档](#cookbook-java.crud.updating)
  + [删除文档](#cookbook-java.crud.deleting)
  + [在一个事务中运行多条语句](#cookbook-java.crud.multi-statement)
  + [重试逻辑](#cookbook-java.crud.retry-logic)
  + [实现唯一限制](#cookbook-java.crud.uniqueness-constraints)
+ [使用 Amazon Ion](#cookbook-java.ion)
  + [导入 Ion 软件包](#cookbook-java.ion.importing)
  + [Ion 初始化](#cookbook-java.ion.initializing)
  + [创建 Ion 对象](#cookbook-java.ion.creating)
  + [读取 Ion 对象](#cookbook-java.ion.reading)

## 导入驱动程序
<a name="cookbook-java.importing"></a>

以下代码示例导入驱动程序、QLDB 会话客户端、Amazon Ion 软件包以及其他相关依赖项。

------
#### [ 2.x ]

```
import com.amazon.ion.IonStruct;
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.system.IonSystemBuilder;

import software.amazon.awssdk.services.qldbsession.QldbSessionClient;
import software.amazon.qldb.QldbDriver;
import software.amazon.qldb.Result;
```

------
#### [ 1.x ]

```
import com.amazon.ion.IonStruct;
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.system.IonSystemBuilder;

import com.amazonaws.services.qldbsession.AmazonQLDBSessionClientBuilder;
import software.amazon.qldb.PooledQldbDriver;
import software.amazon.qldb.Result;
```

------

## 实例化驱动程序
<a name="cookbook-java.instantiating"></a>

以下代码示例创建了连接到指定分类账名称的驱动程序实例，并使用具有自定义重试限制的指定[重试逻辑](#cookbook-java.crud.retry-logic)。

**注意**  
此示例还实例化了 Amazon Ion 系统对象（`IonSystem`）。在本参考中运行某些数据操作时，您需要此对象来处理 Ion 数据。要了解更多信息，请参阅 [使用 Amazon Ion](#cookbook-java.ion)。

------
#### [ 2.x ]

```
QldbDriver qldbDriver = QldbDriver.builder()
    .ledger("vehicle-registration")
    .transactionRetryPolicy(RetryPolicy
        .builder()
        .maxRetries(3)
        .build())
    .sessionClientBuilder(QldbSessionClient.builder())
    .build();

IonSystem SYSTEM = IonSystemBuilder.standard().build();
```

------
#### [ 1.x ]

```
PooledQldbDriver qldbDriver = PooledQldbDriver.builder()
    .withLedger("vehicle-registration")
    .withRetryLimit(3)
    .withSessionClientBuilder(AmazonQLDBSessionClientBuilder.standard())
    .build();

IonSystem SYSTEM = IonSystemBuilder.standard().build();
```

------

## CRUD 操作
<a name="cookbook-java.crud"></a>

QLDB 作为事务的一部分运行*创建、读取、更新和删除*（CRUD）操作。

**警告**  
作为最佳实践，使写事务严格地幂等。

**使事务幂等**

我们建议将写事务设置为幂等，以避免重试时出现任何意想不到的副作用。如果事务可以运行多次并每次都产生相同的结果，则事务是*幂等的*。

例如，假设有一个事务，要将文档插入名为 `Person` 的表中。事务应该首先检查文档是否已经存在于表中。如果没有这种检查，表最终可能会有重复的文档。

假设 QLDB 在服务器端成功提交了事务，但客户端在等待响应时超时。如果事务不是幂等的，则在重试的情况下可以多次插入相同的文档。

**使用索引避免全表扫描**

我们还建议您在索引字段或文档 ID 上使用*相等*运算符来运行带有`WHERE`谓词子句的语句；例如，`WHERE indexedField = 123`或 `WHERE indexedField IN (456, 789)`。如果没有这种索引查找，QLDB 需要进行表扫描，这可能会导致事务超时或*乐观并发控制*（OCC）冲突。

有关 OCC 的更多信息，请参阅[Amazon QLDB 并发模型](concurrency.md)。

**隐式创建的事务**

[QldbDriver.execut](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/software/amazon/qldb/QldbDriver.html) e 方法接受一个 lambda 函数，该函数接收一个 E [xecutor](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/software/amazon/qldb/Executor.html) 的实例，你可以用它来运行语句。`Executor`实例封装了隐式创建的事务。

您可以使用`Executor.execute`方法在 lambda 函数中运行语句。当 lambda 函数返回时，驱动程序会隐式提交事务。

以下各节介绍如何运行基本的 CRUD 操作、指定自定义重试逻辑以及如何实现唯一性约束。

**注意**  
在适用的情况下，这些部分提供了使用内置 Ion 库和 Jackson Ion 映射器库处理 Amazon Ion 数据代码示例。要了解更多信息，请参阅 [使用 Amazon Ion](#cookbook-java.ion)。

**Contents**
+ [创建表](#cookbook-java.crud.creating-tables)
+ [创建索引](#cookbook-java.crud.creating-indexes)
+ [阅读文档](#cookbook-java.crud.reading)
+ [插入文档](#cookbook-java.crud.inserting)
  + [在一条语句内插入多个文档](#cookbook-java.crud.inserting.multiple)
+ [更新文档](#cookbook-java.crud.updating)
+ [删除文档](#cookbook-java.crud.deleting)
+ [在一个事务中运行多条语句](#cookbook-java.crud.multi-statement)
+ [重试逻辑](#cookbook-java.crud.retry-logic)
+ [实现唯一限制](#cookbook-java.crud.uniqueness-constraints)

### 创建表
<a name="cookbook-java.crud.creating-tables"></a>

```
qldbDriver.execute(txn -> {
    txn.execute("CREATE TABLE Person");
});
```

### 创建索引
<a name="cookbook-java.crud.creating-indexes"></a>

```
qldbDriver.execute(txn -> {
    txn.execute("CREATE INDEX ON Person(GovId)");
});
```

### 阅读文档
<a name="cookbook-java.crud.reading"></a>

```
// Assumes that Person table has documents as follows:
// { GovId: "TOYENC486FH", FirstName: "Brent" }

qldbDriver.execute(txn -> {
    Result result = txn.execute("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'");
    IonStruct person = (IonStruct) result.iterator().next();
    System.out.println(person.get("GovId")); // prints TOYENC486FH
    System.out.println(person.get("FirstName")); // prints Brent
});
```

**使用查询参数**

以下代码示例使用 Ion 类型查询参数。

```
qldbDriver.execute(txn -> {
    Result result = txn.execute("SELECT * FROM Person WHERE GovId = ?",
            SYSTEM.newString("TOYENC486FH"));
    IonStruct person = (IonStruct) result.iterator().next();
    System.out.println(person.get("GovId")); // prints TOYENC486FH
    System.out.println(person.get("FirstName")); // prints Brent
});
```

以下代码示例使用了多个查询参数。

```
qldbDriver.execute(txn -> {
    Result result = txn.execute("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?",
            SYSTEM.newString("TOYENC486FH"),
            SYSTEM.newString("Brent"));
    IonStruct person = (IonStruct) result.iterator().next();
    System.out.println(person.get("GovId")); // prints TOYENC486FH
    System.out.println(person.get("FirstName")); // prints Brent
});
```

以下代码示例使用查询参数列表。

```
qldbDriver.execute(txn -> {
    final List<IonValue> parameters = new ArrayList<>();
    parameters.add(SYSTEM.newString("TOYENC486FH"));
    parameters.add(SYSTEM.newString("ROEE1"));
    parameters.add(SYSTEM.newString("YH844"));
    Result result = txn.execute("SELECT * FROM Person WHERE GovId IN (?,?,?)", parameters);
    IonStruct person = (IonStruct) result.iterator().next();
    System.out.println(person.get("GovId")); // prints TOYENC486FH
    System.out.println(person.get("FirstName")); // prints Brent
});
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.crud.reading.jackson"></a>

```
// Assumes that Person table has documents as follows:
// {GovId: "TOYENC486FH", FirstName: "Brent" }

qldbDriver.execute(txn -> {
    try {
        Result result = txn.execute("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'");
        Person person = MAPPER.readValue(result.iterator().next(), Person.class);
        System.out.println(person.getFirstName()); // prints Brent
        System.out.println(person.getGovId()); // prints TOYENC486FH
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

**使用查询参数**

以下代码示例使用 Ion 类型查询参数。

```
qldbDriver.execute(txn -> {
    try {
        Result result = txn.execute("SELECT * FROM Person WHERE GovId = ?",
                MAPPER.writeValueAsIonValue("TOYENC486FH"));
        Person person = MAPPER.readValue(result.iterator().next(), Person.class);
        System.out.println(person.getFirstName()); // prints Brent
        System.out.println(person.getGovId()); // prints TOYENC486FH
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

以下代码示例使用了多个查询参数。

```
qldbDriver.execute(txn -> {
    try {
        Result result = txn.execute("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?",
                MAPPER.writeValueAsIonValue("TOYENC486FH"),
                MAPPER.writeValueAsIonValue("Brent"));
        Person person = MAPPER.readValue(result.iterator().next(), Person.class);
        System.out.println(person.getFirstName()); // prints Brent
        System.out.println(person.getGovId()); // prints TOYENC486FH
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

以下代码示例使用查询参数列表。

```
qldbDriver.execute(txn -> {
    try {
        final List<IonValue> parameters = new ArrayList<>();
        parameters.add(MAPPER.writeValueAsIonValue("TOYENC486FH"));
        parameters.add(MAPPER.writeValueAsIonValue("ROEE1"));
        parameters.add(MAPPER.writeValueAsIonValue("YH844"));
        Result result = txn.execute("SELECT * FROM Person WHERE GovId IN (?,?,?)", parameters);
        Person person = MAPPER.readValue(result.iterator().next(), Person.class);
        System.out.println(person.getFirstName()); // prints Brent
        System.out.println(person.getGovId()); // prints TOYENC486FH
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

**注意**  
当您在没有索引查找的情况下运行查询时，它会调用全表扫描。在此示例中，我们建议在`GovId`字段上设置 [索引](ql-reference.create-index.md)以优化性能。如果不开启`GovId`索引，查询可能会有更长的延迟，还可能导致 OCC 冲突异常或者事务超时。

### 插入文档
<a name="cookbook-java.crud.inserting"></a>

以下代码示例插入 Ion 数据类型。

```
qldbDriver.execute(txn -> {
    // Check if a document with GovId:TOYENC486FH exists
    // This is critical to make this transaction idempotent
    Result result = txn.execute("SELECT * FROM Person WHERE GovId = ?",
            SYSTEM.newString("TOYENC486FH"));
    // Check if there is a result
    if (!result.iterator().hasNext()) {
        IonStruct person = SYSTEM.newEmptyStruct();
        person.put("GovId").newString("TOYENC486FH");
        person.put("FirstName").newString("Brent");
        // Insert the document
        txn.execute("INSERT INTO Person ?", person);
    }
});
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.crud.inserting.jackson"></a>

以下代码示例插入 Ion 数据类型。

```
qldbDriver.execute(txn -> {
    try {
        // Check if a document with GovId:TOYENC486FH exists
        // This is critical to make this transaction idempotent
        Result result = txn.execute("SELECT * FROM Person WHERE GovId = ?",
                MAPPER.writeValueAsIonValue("TOYENC486FH"));
        // Check if there is a result
        if (!result.iterator().hasNext()) {
            // Insert the document
            txn.execute("INSERT INTO Person ?",
                    MAPPER.writeValueAsIonValue(new Person("Brent", "TOYENC486FH")));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

此事务将文档插入 `Person` 表中。在插入之前，它首先检查文档是否已存在于表格内。**此检查使事务本质上是幂等。**即使您多次运行此事务，也不会造成任何异常副作用。

**注意**  
在此示例中，我们建议在 `GovId` 字段上设置索引以优化性能。如果不开启`GovId`索引，语句可能会有更长的延迟，还可能导致 OCC 冲突异常或者事务超时。

#### 在一条语句内插入多个文档
<a name="cookbook-java.crud.inserting.multiple"></a>

要使用单个[INSERT](ql-reference.insert.md)语句插入多个文档，可以向该语句传递一个类型的参数 [IonList](driver-working-with-ion.md#driver-ion-list)（显式转换为`IonValue`），如下所示。

```
// people is an IonList explicitly cast as an IonValue
txn.execute("INSERT INTO People ?", (IonValue) people);
```

传递 `IonList` 列表时，不要将变量占位符（`?`）包括在双尖括号（ `<<...>>` ）内。在手动 PartiQL 语句中，双尖括号表示名为*bag*的无序集合。

##### 为什么需要显式转换？
<a name="cookbook-java.crud.inserting.multiple.cast"></a>

[TransactionExecutor.execute](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/software/amazon/qldb/TransactionExecutor.html) 方法已过载。它接受可变数量的 `IonValue`参数（*varargs*）或单个`List<IonValue>`参数。在 [ion-java](https://www.javadoc.io/doc/com.amazon.ion/ion-java/latest/index.html) 中，`IonList` 被实现为`List<IonValue>`。

当您调用重载方法，Java 默认其为最具体的实施方法。在这种情况下，当您传递 `IonList` 参数时，它默认为采用`List<IonValue>`。调用时，此方法实现会将列表中的`IonValue`元素作为不同的值传递。因此，要改为调用 varargs 方法，必须将`IonList`参数显式转换为`IonValue`。

### 更新文档
<a name="cookbook-java.crud.updating"></a>

```
qldbDriver.execute(txn -> {
    final List<IonValue> parameters = new ArrayList<>();
    parameters.add(SYSTEM.newString("John"));
    parameters.add(SYSTEM.newString("TOYENC486FH"));
    txn.execute("UPDATE Person SET FirstName = ? WHERE GovId = ?", parameters);
});
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.crud.updating.jackson"></a>

```
qldbDriver.execute(txn -> {
    try {
        final List<IonValue> parameters = new ArrayList<>();
        parameters.add(MAPPER.writeValueAsIonValue("John"));
        parameters.add(MAPPER.writeValueAsIonValue("TOYENC486FH"));
        txn.execute("UPDATE Person SET FirstName = ? WHERE GovId = ?", parameters);
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

**注意**  
在此示例中，我们建议在 `GovId` 字段上设置索引以优化性能。如果不开启`GovId`索引，语句可能会有更长的延迟，还可能导致 OCC 冲突异常或者事务超时。

### 删除文档
<a name="cookbook-java.crud.deleting"></a>

```
qldbDriver.execute(txn -> {
    txn.execute("DELETE FROM Person WHERE GovId = ?",
            SYSTEM.newString("TOYENC486FH"));
});
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.crud.deleting.jackson"></a>

```
qldbDriver.execute(txn -> {
    try {
        txn.execute("DELETE FROM Person WHERE GovId = ?",
                MAPPER.writeValueAsIonValue("TOYENC486FH"));
    } catch (IOException e) {
        e.printStackTrace();
    }
});
```

**注意**  
在此示例中，我们建议在 `GovId` 字段上设置索引以优化性能。如果不开启`GovId`索引，语句可能会有更长的延迟，还可能导致 OCC 冲突异常或者事务超时。

### 在一个事务中运行多条语句
<a name="cookbook-java.crud.multi-statement"></a>

```
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd
// set your UPDATE to filter on vin and insured, and check if you updated something or not.
public static boolean InsureCar(QldbDriver qldbDriver, final String vin) {
    final IonSystem ionSystem = IonSystemBuilder.standard().build();
    final IonString ionVin = ionSystem.newString(vin);

    return qldbDriver.execute(txn -> {
        Result result = txn.execute(
                "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE",
                ionVin);
        if (!result.isEmpty()) {
            txn.execute("UPDATE Vehicles SET insured = TRUE WHERE vin = ?", ionVin);
            return true;
        }
        return false;
    });
}
```

### 重试逻辑
<a name="cookbook-java.crud.retry-logic"></a>

驱动程序 `execute` 方法具有内置的重试机制，如果发生可重试的异常（例如超时或 OCC 冲突），该机制可以重试事务。

------
#### [ 2.x ]

最大重试次数和退避策略为可配置。

默认重试限制为`4`，默认退避策略为。[DefaultQldbTransactionBackoffStrategy](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/software/amazon/qldb/DefaultQldbTransactionBackoffStrategy.html)您可以使用的实例为每个驱动程序实例以及每个事务设置重试配置。[RetryPolicy](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/software/amazon/qldb/RetryPolicy.html)

以下代码示例使用自定义重试限制和驱动程序实例的自定义退避策略指定重试逻辑。

```
public void retry() {
    QldbDriver qldbDriver = QldbDriver.builder()
            .ledger("vehicle-registration")
            .transactionRetryPolicy(RetryPolicy.builder()
                    .maxRetries(2)
                    .backoffStrategy(new CustomBackOffStrategy()).build())
            .sessionClientBuilder(QldbSessionClient.builder())
            .build();
}

private class CustomBackOffStrategy implements BackoffStrategy {

    @Override
    public Duration calculateDelay(RetryPolicyContext retryPolicyContext) {
        return Duration.ofMillis(1000 * retryPolicyContext.retriesAttempted());
    }
}
```

以下代码示例使用自定义重试限制和自定义回退策略指定重试逻辑。此`execute`配置将覆盖为驱动程序实例设置的重试逻辑。

```
public void retry() {
    Result result = qldbDriver.execute(txn -> { txn.execute("SELECT * FROM Person WHERE GovId = ?",
            SYSTEM.newString("TOYENC486FH")); },
            RetryPolicy.builder()
                    .maxRetries(2)
                    .backoffStrategy(new CustomBackOffStrategy())
                    .build());
}

private class CustomBackOffStrategy implements BackoffStrategy {

    // Configuring a custom backoff which increases delay by 1s for each attempt.
    @Override
    public Duration calculateDelay(RetryPolicyContext retryPolicyContext) {
        return Duration.ofMillis(1000 * retryPolicyContext.retriesAttempted());
    }
}
```

------
#### [ 1.x ]

最大重试次数。您可以通过在初始化`PooledQldbDriver` 时设置 `retryLimit` 属性来配置重试限制。

默认重试限制为 `4`。

------

### 实现唯一限制
<a name="cookbook-java.crud.uniqueness-constraints"></a>

QLDB 不支持唯一索引，但您可在应用程序中实现此行为。

假设您要对 `Person` 表中的 `GovId` 字段实现唯一性约束。据此，可以编写执行以下操作的事务：

1. 断言该表中没有指定 `GovId` 的现有文档。

1. 如果断言通过，请插入文档。

如果一个竞争事务同时通过断言，则只有一个事务将成功提交。另一笔事务将失败，并显示 OCC 冲突异常。

以下代码示例显示了如何实现此唯一约束。

```
qldbDriver.execute(txn -> {
    Result result = txn.execute("SELECT * FROM Person WHERE GovId = ?",
            SYSTEM.newString("TOYENC486FH"));
    // Check if there is a result
    if (!result.iterator().hasNext()) {
        IonStruct person = SYSTEM.newEmptyStruct();
        person.put("GovId").newString("TOYENC486FH");
        person.put("FirstName").newString("Brent");
        // Insert the document
        txn.execute("INSERT INTO Person ?", person);
    }
});
```

**注意**  
在此示例中，我们建议在 `GovId` 字段上设置索引以优化性能。如果不开启`GovId`索引，语句可能会有更长的延迟，还可能导致 OCC 冲突异常或者事务超时。

## 使用 Amazon Ion
<a name="cookbook-java.ion"></a>

可通过多种方法在 QLDB 中处理 Amazon Ion 数据。您可根据需要使用 [Ion 库](https://github.com/amzn/ion-java) 中的内置方法，灵活创建和修改文档。或者，您可以使用 FasterXML 的 [Jackson Ion 数据格式模块](https://github.com/FasterXML/jackson-dataformats-binary/tree/master/ion)，以将 Ion 文档映射至*普通旧 Java 对象*（POJO）模型。

以下各节提供了使用这两种技术处理 Ion 数据的代码示例。

**Contents**
+ [导入 Ion 软件包](#cookbook-java.ion.importing)
+ [Ion 初始化](#cookbook-java.ion.initializing)
+ [创建 Ion 对象](#cookbook-java.ion.creating)
+ [读取 Ion 对象](#cookbook-java.ion.reading)

### 导入 Ion 软件包
<a name="cookbook-java.ion.importing"></a>

将工件 [ion-java](https://search.maven.org/artifact/com.amazon.ion/ion-java/1.6.1/bundle) 作为依赖项添加至您的 Java 项目。

------
#### [ Gradle ]

```
dependencies {
    compile group: 'com.amazon.ion', name: 'ion-java', version: '1.6.1'
}
```

------
#### [ Maven ]

```
<dependencies>
  <dependency>
    <groupId>com.amazon.ion</groupId>
    <artifactId>ion-java</artifactId>
    <version>1.6.1</version>
  </dependency>
</dependencies>
```

------

导入以下 Ion 软件包。

```
import com.amazon.ion.IonStruct;
import com.amazon.ion.IonSystem;
import com.amazon.ion.system.IonSystemBuilder;
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.ion.importing.jackson"></a>

将构件[jackson-dataformat-ion](https://search.maven.org/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-ion/2.10.0/bundle)作为依赖项添加到 Java 项目中。QLDB 需要 `2.10.0` 版本或以上版本。

------
#### [ Gradle ]

```
dependencies {
    compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-ion', version: '2.10.0'
}
```

------
#### [ Maven ]

```
<dependencies>
  <dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-ion</artifactId>
    <version>2.10.0</version>
  </dependency>
</dependencies>
```

------

导入以下 Ion 软件包。

```
import com.amazon.ion.IonReader;
import com.amazon.ion.IonStruct;
import com.amazon.ion.system.IonReaderBuilder;
import com.amazon.ion.system.IonSystemBuilder;

import com.fasterxml.jackson.dataformat.ion.IonObjectMapper;
import com.fasterxml.jackson.dataformat.ion.ionvalue.IonValueMapper;
```

### Ion 初始化
<a name="cookbook-java.ion.initializing"></a>

```
IonSystem SYSTEM = IonSystemBuilder.standard().build();
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.ion.initializing.jackson"></a>

```
IonObjectMapper MAPPER = new IonValueMapper(IonSystemBuilder.standard().build());
```

### 创建 Ion 对象
<a name="cookbook-java.ion.creating"></a>

以下代码示例使用 `IonStruct` 接口及其内置方法创建 Ion 对象。

```
IonStruct ionStruct = SYSTEM.newEmptyStruct();

ionStruct.put("GovId").newString("TOYENC486FH");
ionStruct.put("FirstName").newString("Brent");

System.out.println(ionStruct.toPrettyString()); // prints a nicely formatted copy of ionStruct
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.ion.creating.jackson"></a>

假设您有名为 JSON 映射的模型类`Person`，如下所示。

```
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public static class Person {
    private final String firstName;
    private final String govId;

    @JsonCreator
    public Person(@JsonProperty("FirstName") final String firstName,
                  @JsonProperty("GovId") final String govId) {
        this.firstName = firstName;
        this.govId = govId;
    }

    @JsonProperty("FirstName")
    public String getFirstName() {
        return firstName;
    }

    @JsonProperty("GovId")
    public String getGovId() {
        return govId;
    }
}
```

以下代码示例根据`IonStruct`实例创建对象`Person`。

```
IonStruct ionStruct = (IonStruct) MAPPER.writeValueAsIonValue(new Person("Brent", "TOYENC486FH"));
```

### 读取 Ion 对象
<a name="cookbook-java.ion.reading"></a>

以下代码示例打印 `ionStruct` 实例的每个字段。

```
// ionStruct is an instance of IonStruct
System.out.println(ionStruct.get("GovId")); // prints TOYENC486FH
System.out.println(ionStruct.get("FirstName")); // prints Brent
```

#### 使用 Jackson 映射程序
<a name="cookbook-java.ion.reading.jackson"></a>

以下代码示例读取一个 `IonStruct` 对象并将其映射到的实例`Person`。

```
// ionStruct is an instance of IonStruct
IonReader reader = IonReaderBuilder.standard().build(ionStruct);
Person person = MAPPER.readValue(reader, Person.class);
System.out.println(person.getFirstName()); // prints Brent
System.out.println(person.getGovId()); // prints TOYENC486FH
```

有关使用 Ion 的更多信息，请参阅上的 [Amazon Ion 文档](http://amzn.github.io/ion-docs/) GitHub。有关在 QLDB 中使用 Ion 的更多代码示例，请参阅[使用 Amazon QLDB 中的 Amazon Ion 数据类型](driver-working-with-ion.md)。