

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 適用於 Python 的 Amazon QLDB 驅動程式
<a name="getting-started.python"></a>

**重要**  
支援終止通知：現有客戶將可以使用 Amazon QLDB，直到 07/31/2025 的支援結束為止。如需詳細資訊，請參閱[將 Amazon QLDB Ledger 遷移至 Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

若要使用 分類帳中的資料，您可以使用 AWS 提供的驅動程式，從 Python 應用程式連線至 Amazon QLDB。下列主題說明如何開始使用適用於 Python 的 QLDB 驅動程式。

**Topics**
+ [驅動程式資源](#getting-started.python.resources)
+ [先決條件](#getting-started.python.prereqs)
+ [安裝](#getting-started.python.install)
+ [快速入門教學課程](driver-quickstart-python.md)
+ [技術指南參考](driver-cookbook-python.md)

## 驅動程式資源
<a name="getting-started.python.resources"></a>

如需 Python 驅動程式支援功能的詳細資訊，請參閱下列資源：
+ API 參考：[3.x](https://amazon-qldb-driver-python.readthedocs.io/en/latest/)、[2.x](https://amazon-qldb-driver-python.readthedocs.io/en/v2.0.2/)
+ [驅動程式原始碼 (GitHub)](https://github.com/awslabs/amazon-qldb-driver-python)
+ [應用程式原始程式碼範例 (GitHub)](https://github.com/aws-samples/amazon-qldb-dmv-sample-python)
+ [Amazon Ion 程式碼範例](ion.code-examples.md)

## 先決條件
<a name="getting-started.python.prereqs"></a>

開始使用適用於 Python 的 QLDB 驅動程式之前，您必須執行下列動作：

1. 請遵循 中的 AWS 設定指示[存取 Amazon QLDB](accessing.md)。這包含下列項目：

   1. 註冊 AWS。

   1. 建立具有適當 QLDB 許可的使用者。

   1. 授予開發的程式設計存取權。

1. 從 Python [下載網站安裝下列其中一個版本的 Python](https://www.python.org/downloads/)：
   + **3.6 或更新版本** – Python v3 的 QLDB 驅動程式
   + **3.4 或更新版本** – Python v2 的 QLDB 驅動程式

1. 設定您的 AWS 登入資料和預設值 AWS 區域。如需說明，請參閱 適用於 Python (Boto3) 的 AWS SDK 文件中的 [Quickstart](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration)。

   如需可用區域的完整清單，請參閱 中的 [Amazon QLDB 端點和配額](https://docs.aws.amazon.com/general/latest/gr/qldb.html)*AWS 一般參考*。

接下來，您可以下載完整的教學課程範例應用程式，或者您只能在 Python 專案中安裝驅動程式，並執行短程式碼範例。
+ 若要在現有專案 適用於 Python (Boto3) 的 AWS SDK 中安裝 QLDB 驅動程式和 ，請繼續[安裝](#getting-started.python.install)。
+ 若要設定專案並執行示範分類帳上基本資料交易的簡短程式碼範例，請參閱 [快速入門教學課程](driver-quickstart-python.md)。
+ 若要在完整的教學課程範例應用程式中執行更深入的資料和管理 API 操作範例，請參閱 [Python 教學課程](getting-started.python.tutorial.md)。

## 安裝
<a name="getting-started.python.install"></a>

QLDB 支援下列驅動程式版本及其 Python 相依性。


****  

| 驅動程式版本 | Python 版本 | Status | 最新發行日期 | 
| --- | --- | --- | --- | 
| [2.x](https://pypi.org/project/pyqldb/2.0.2/) | 3.4 或更新版本 | 生產版本 | 2020 年 5 月 7 日 | 
| [3.x](https://pypi.org/project/pyqldb/) | 3.6 或更新版本 | 生產版本 | 2021 年 10 月 28 日 | 

若要使用 `pip`(Python 的套件管理員） 從 PyPI 安裝 QLDB 驅動程式，請在命令列輸入下列內容。

------
#### [ 3.x ]

```
pip install pyqldb
```

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

```
pip install pyqldb==2.0.2
```

------

安裝驅動程式也會安裝其相依性，包括 [適用於 Python (Boto3) 的 AWS SDK](https://aws.amazon.com/sdk-for-python)和 [Amazon Ion](ion.md) 套件。

**使用驅動程式連線至分類帳**

然後，您可以匯入驅動程式，並使用它連接到分類帳。下列 Python 程式碼範例示範如何為指定的分類帳名稱建立工作階段。

------
#### [ 3.x ]

```
from pyqldb.driver.qldb_driver import QldbDriver
qldb_driver = QldbDriver(ledger_name='testLedger')

for table in qldb_driver.list_tables():
    print(table)
```

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

```
from pyqldb.driver.pooled_qldb_driver import PooledQldbDriver

qldb_driver = PooledQldbDriver(ledger_name='testLedger')
qldb_session = qldb_driver.get_session()

for table in qldb_session.list_tables():
    print(table)
```

------

如需如何在分類帳上執行基本資料交易的簡短程式碼範例，請參閱 [技術指南參考](driver-cookbook-python.md)。

# Python 的 Amazon QLDB 驅動程式 – 快速入門教學課程
<a name="driver-quickstart-python"></a>

**重要**  
支援終止通知：現有客戶將可以使用 Amazon QLDB，直到 07/31/2025 的支援結束為止。如需詳細資訊，請參閱[將 Amazon QLDB Ledger 遷移至 Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

在本教學課程中，您將了解如何使用最新版本的 Python Amazon QLDB 驅動程式來設定簡單的應用程式。本指南包含安裝驅動程式的步驟，以及基本*建立、讀取、更新和刪除* (CRUD) 操作的簡短程式碼範例。如需在完整範例應用程式中示範這些操作的更深入範例，請參閱 [Python 教學課程](getting-started.python.tutorial.md)。

**Topics**
+ [先決條件](#driver-quickstart-python.prereqs)
+ [步驟 1：設定您的 專案](#driver-quickstart-python.step-1)
+ [步驟 2：初始化驅動程式](#driver-quickstart-python.step-2)
+ [步驟 3：建立資料表和索引](#driver-quickstart-python.step-3)
+ [步驟 4：插入文件](#driver-quickstart-python.step-4)
+ [步驟 5：查詢文件](#driver-quickstart-python.step-5)
+ [步驟 6：更新文件](#driver-quickstart-python.step-6)
+ [執行完整的應用程式](#driver-quickstart-python.complete)

## 先決條件
<a name="driver-quickstart-python.prereqs"></a>

開始之前，請務必執行下列動作：

1. 如果您尚未執行此操作，請完成 Python 驅動程式[先決條件](getting-started.python.md#getting-started.python.prereqs)的 。這包括註冊 AWS、授予開發的程式設計存取權，以及安裝 Python 3.6 版或更新版本。

1. 建立名為 的分類帳`quick-start`。

   若要了解如何建立分類帳，請參閱 主控台入門[步驟 1：建立新的分類帳](getting-started-step-1.md)中的 [Amazon QLDB 分類帳的基本操作](ledger-management.basics.md)或 。 **

## 步驟 1：設定您的 專案
<a name="driver-quickstart-python.step-1"></a>

首先，設定您的 Python 專案。

**注意**  
如果您使用具有自動化這些設定步驟功能的 IDE，您可以直接跳到 [步驟 2：初始化驅動程式](#driver-quickstart-python.step-2)。

1. 為您的應用程式建立資料夾。

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

1. 若要從 PyPI 安裝適用於 Python 的 QLDB 驅動程式，請輸入下列`pip`命令。

   ```
   $ pip install pyqldb
   ```

   安裝驅動程式也會安裝其相依性，包括 [適用於 Python (Boto3) 的 AWS SDK](https://aws.amazon.com/sdk-for-net)和 [Amazon Ion](ion.md) 套件。

1. 建立名為 `app.py` 的新檔案。

   然後，在下列步驟中逐步新增程式碼範例，以嘗試一些基本的 CRUD 操作。或者，您可以略過step-by-step教學課程，改為執行[完整的應用程式](#driver-quickstart-python.complete)。

## 步驟 2：初始化驅動程式
<a name="driver-quickstart-python.step-2"></a>

初始化連接至名為 之分類帳的驅動程式執行個體`quick-start`。將下列程式碼新增至您的 `app.py` 檔案。

```
from pyqldb.config.retry_config import RetryConfig
from pyqldb.driver.qldb_driver import QldbDriver

# Configure retry limit to 3
retry_config = RetryConfig(retry_limit=3)

# Initialize the driver
print("Initializing the driver")
qldb_driver = QldbDriver("quick-start", retry_config=retry_config)
```

## 步驟 3：建立資料表和索引
<a name="driver-quickstart-python.step-3"></a>

下列程式碼範例示範如何執行 `CREATE TABLE`和 `CREATE INDEX`陳述式。

新增下列程式碼，為該資料表上的 `lastName` 欄位建立名為 的資料表`People`和索引。需要[索引](ql-reference.create-index.md)才能最佳化查詢效能，並協助限制[樂觀並行控制 (OCC)](concurrency.md) 衝突例外狀況。

```
def create_table(transaction_executor):
    print("Creating a table")
    transaction_executor.execute_statement("Create TABLE People")

def create_index(transaction_executor):
    print("Creating an index")
    transaction_executor.execute_statement("CREATE INDEX ON People(lastName)")

# Create a table
qldb_driver.execute_lambda(lambda executor: create_table(executor))

# Create an index on the table
qldb_driver.execute_lambda(lambda executor: create_index(executor))
```

## 步驟 4：插入文件
<a name="driver-quickstart-python.step-4"></a>

下列程式碼範例示範如何執行 `INSERT`陳述式。QLDB 支援 [PartiQL](ql-reference.md) 查詢語言 （與 SQL 相容） 和 [Amazon Ion](ion.md) 資料格式 (JSON 的超集）。

新增下列程式碼，將文件插入`People`資料表。

```
def insert_documents(transaction_executor, arg_1):
    print("Inserting a document")
    transaction_executor.execute_statement("INSERT INTO People ?", arg_1)

# Insert a document
doc_1 = { 'firstName': "John",
          'lastName': "Doe",
          'age': 32,
        }

qldb_driver.execute_lambda(lambda x: insert_documents(x, doc_1))
```

此範例使用問號 (`?`) 做為變數預留位置，將文件資訊傳遞至 陳述式。此`execute_statement`方法支援 Amazon Ion 類型和 Python 原生類型的值。

**提示**  
若要使用單一[INSERT](ql-reference.insert.md)陳述式插入多個文件，您可以將類型[清單](driver-working-with-ion.md#driver-ion-list)的參數傳遞至陳述式，如下所示。  

```
# people is a list
transaction_executor.execute_statement("INSERT INTO Person ?", people)
```
傳遞清單時，您不會將變數預留位置 (`?`) 括在雙角度括號 ( ) `<<...>>` 中。在手動 PartiQL 陳述式中，雙角括號表示稱為*包*的未排序集合。

## 步驟 5：查詢文件
<a name="driver-quickstart-python.step-5"></a>

下列程式碼範例示範如何執行 `SELECT`陳述式。

新增下列程式碼，以查詢`People`資料表中的文件。

```
def read_documents(transaction_executor):
    print("Querying the table")
    cursor = transaction_executor.execute_statement("SELECT * FROM People WHERE lastName = ?", 'Doe')

    for doc in cursor:
        print(doc["firstName"])
        print(doc["lastName"])
        print(doc["age"])

# Query the table
qldb_driver.execute_lambda(lambda executor: read_documents(executor))
```

## 步驟 6：更新文件
<a name="driver-quickstart-python.step-6"></a>

下列程式碼範例示範如何執行 `UPDATE`陳述式。

1. 新增下列程式碼，透過更新 `age` 來更新`People`資料表中的文件`42`。

   ```
   def update_documents(transaction_executor, age, lastName):
       print("Updating the document")
       transaction_executor.execute_statement("UPDATE People SET age = ? WHERE lastName = ?", age, lastName)
   
   # Update the document
   age = 42
   lastName = 'Doe'
   
   qldb_driver.execute_lambda(lambda x: update_documents(x, age, lastName))
   ```

1. 再次查詢資料表以查看更新的值。

   ```
   # Query the updated document
   qldb_driver.execute_lambda(lambda executor: read_documents(executor))
   ```

1. 若要執行應用程式，請從專案目錄輸入下列命令。

   ```
   $ python app.py
   ```

## 執行完整的應用程式
<a name="driver-quickstart-python.complete"></a>

下列程式碼範例是`app.py`應用程式的完整版本。您也可以從頭到尾複製並執行此程式碼範例，而不是個別執行上述步驟。此應用程式會在名為 的分類帳上示範一些基本 CRUD 操作`quick-start`。

**注意**  
在您執行此程式碼之前，請確定您尚未在 分類帳`People`中擁有名為 `quick-start` 的作用中資料表。

```
from pyqldb.config.retry_config import RetryConfig
from pyqldb.driver.qldb_driver import QldbDriver

def create_table(transaction_executor):
    print("Creating a table")
    transaction_executor.execute_statement("CREATE TABLE People")

def create_index(transaction_executor):
    print("Creating an index")
    transaction_executor.execute_statement("CREATE INDEX ON People(lastName)")

def insert_documents(transaction_executor, arg_1):
    print("Inserting a document")
    transaction_executor.execute_statement("INSERT INTO People ?", arg_1)

def read_documents(transaction_executor):
    print("Querying the table")
    cursor = transaction_executor.execute_statement("SELECT * FROM People WHERE lastName = ?", 'Doe')
                                                                                                                                          
    for doc in cursor:
        print(doc["firstName"])
        print(doc["lastName"])
        print(doc["age"])

def update_documents(transaction_executor, age, lastName):
    print("Updating the document")
    transaction_executor.execute_statement("UPDATE People SET age = ? WHERE lastName = ?", age, lastName)

# Configure retry limit to 3
retry_config = RetryConfig(retry_limit=3)

# Initialize the driver
print("Initializing the driver")
qldb_driver = QldbDriver("quick-start", retry_config=retry_config)

# Create a table
qldb_driver.execute_lambda(lambda executor: create_table(executor))

# Create an index on the table
qldb_driver.execute_lambda(lambda executor: create_index(executor))

# Insert a document
doc_1 = { 'firstName': "John",
          'lastName': "Doe",
          'age': 32,
        }

qldb_driver.execute_lambda(lambda x: insert_documents(x, doc_1))

# Query the table
qldb_driver.execute_lambda(lambda executor: read_documents(executor))

# Update the document
age = 42
lastName = 'Doe'

qldb_driver.execute_lambda(lambda x: update_documents(x, age, lastName))

# Query the table for the updated document
qldb_driver.execute_lambda(lambda executor: read_documents(executor))
```

若要執行完整的應用程式，請從專案目錄中輸入下列命令。

```
$ python app.py
```

# Python 的 Amazon QLDB 驅動程式 – 技術指南參考
<a name="driver-cookbook-python"></a>

**重要**  
支援終止通知：現有客戶將可以使用 Amazon QLDB，直到 07/31/2025 的支援結束為止。如需詳細資訊，請參閱[將 Amazon QLDB Ledger 遷移至 Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

此參考指南顯示適用於 Python 的 Amazon QLDB 驅動程式的常見使用案例。它提供 Python 程式碼範例，示範如何使用驅動程式執行基本的*建立、讀取、更新和刪除* (CRUD) 操作。它也包含處理 Amazon Ion 資料的程式碼範例。此外，本指南重點介紹了建立交易等冪和實作唯一性限制的最佳實務。

**注意**  
在適用的情況下，某些使用案例對於 Python 的 QLDB 驅動程式的每個支援主要版本都有不同的程式碼範例。

**Contents**
+ [匯入驅動程式](#cookbook-python.importing)
+ [執行個體化驅動程式](#cookbook-python.instantiating)
+ [CRUD 操作](#cookbook-python.crud)
  + [建立資料表](#cookbook-python.crud.creating-tables)
  + [建立索引](#cookbook-python.crud.creating-indexes)
  + [讀取文件](#cookbook-python.crud.reading)
    + [使用查詢參數](#cookbook-python.reading-using-params)
  + [插入文件](#cookbook-python.crud.inserting)
    + [在一個陳述式中插入多個文件](#cookbook-python.crud.inserting.multiple)
  + [更新文件](#cookbook-python.crud.updating)
  + [刪除文件](#cookbook-python.crud.deleting)
  + [在交易中執行多個陳述式](#cookbook-python.crud.multi-statement)
  + [重試邏輯](#cookbook-python.crud.retry-logic)
  + [實作唯一性限制](#cookbook-python.crud.uniqueness-constraints)
+ [使用 Amazon Ion](#cookbook-python.ion)
  + [匯入 Ion 模組](#cookbook-python.ion.import)
  + [建立 Ion 類型](#cookbook-python.ion.creating-types)
  + [取得 Ion 二進位傾印](#cookbook-python.ion.getting-binary)
  + [取得 Ion 文字傾印](#cookbook-python.ion.getting-text)

## 匯入驅動程式
<a name="cookbook-python.importing"></a>

下列程式碼範例會匯入驅動程式。

------
#### [ 3.x ]

```
from pyqldb.driver.qldb_driver import QldbDriver
import amazon.ion.simpleion as simpleion
```

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

```
from pyqldb.driver.pooled_qldb_driver import PooledQldbDriver
import amazon.ion.simpleion as simpleion
```

------

**注意**  
此範例也會匯入 Amazon Ion 套件 (`amazon.ion.simpleion`)。您需要此套件，才能在此參考中執行某些資料操作時處理 Ion 資料。如需進一步了解，請參閱 [使用 Amazon Ion](#cookbook-python.ion)。

## 執行個體化驅動程式
<a name="cookbook-python.instantiating"></a>

下列程式碼範例會建立驅動程式的執行個體，使用預設設定連線至指定的分類帳名稱。

------
#### [ 3.x ]

```
qldb_driver = QldbDriver(ledger_name='vehicle-registration')
```

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

```
qldb_driver = PooledQldbDriver(ledger_name='vehicle-registration')
```

------

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

QLDB 會在交易中執行*建立、讀取、更新和刪除* (CRUD) 操作。

**警告**  
最佳實務是，讓您的寫入交易具有嚴格等冪性。

**使交易具有等冪性**

我們建議您將寫入交易設為等冪，以避免重試時發生任何非預期的副作用。如果交易可以多次執行，並且每次產生相同的結果，則交易是*等*冪的。

例如，請考慮將文件插入名為 的資料表的交易`Person`。交易應先檢查資料表中是否已存在該文件。如果沒有此檢查，資料表最終可能會顯示重複的文件。

假設 QLDB 在伺服器端成功遞交交易，但用戶端在等待回應時逾時。如果交易不等冪，在重試的情況下，相同的文件可以插入多次。

**使用索引來避免完整資料表掃描**

我們也建議您在索引欄位或文件 ID 上使用*等式*運算子，使用`WHERE`述詞子來執行陳述式；例如， `WHERE indexedField = 123`或 `WHERE indexedField IN (456, 789)`。如果沒有此索引查詢，QLDB 需要執行資料表掃描，這可能會導致交易逾時或*樂觀並行控制* (OCC) 衝突。

如需 OCC 的詳細資訊，請參閱 [Amazon QLDB 並行模型](concurrency.md)。

**隱含建立的交易**

[pyqldb.driver.qldb\$1driver.execute\$1lambda](https://amazon-qldb-driver-python.readthedocs.io/en/stable/reference/driver/qldb_driver.html#pyqldb.driver.qldb_driver.QldbDriver.execute_lambda) 方法接受 lambda 函數，該函數會接收 [pyqldb.execution.executor.Executor](https://amazon-qldb-driver-python.readthedocs.io/en/stable/reference/execution/executor.html#pyqldb.execution.executor.Executor) 的執行個體，您可以使用該函數來執行陳述式。執行個體會`Executor`包裝隱含建立的交易。

您可以使用交易執行器的 [execute\$1statement](https://amazon-qldb-driver-python.readthedocs.io/en/stable/reference/execution/executor.html#pyqldb.execution.executor.Executor.execute_statement) 方法，在 lambda 函數中執行陳述式。當 lambda 函數傳回時，驅動程式會隱含遞交交易。

**注意**  
此`execute_statement`方法同時支援 Amazon Ion 類型和 Python 原生類型。如果您將 Python 原生類型做為引數傳遞至 `execute_statement`，驅動程式會使用 `amazon.ion.simpleion`模組將其轉換為 Ion 類型 （前提是支援指定 Python 資料類型的轉換）。如需支援的資料類型和轉換規則，請參閱[簡易原始程式碼](https://ion-python.readthedocs.io/en/latest/_modules/amazon/ion/simpleion.html)。

下列各節說明如何執行基本 CRUD 操作、指定自訂重試邏輯，以及實作唯一性限制條件。

**Contents**
+ [建立資料表](#cookbook-python.crud.creating-tables)
+ [建立索引](#cookbook-python.crud.creating-indexes)
+ [讀取文件](#cookbook-python.crud.reading)
  + [使用查詢參數](#cookbook-python.reading-using-params)
+ [插入文件](#cookbook-python.crud.inserting)
  + [在一個陳述式中插入多個文件](#cookbook-python.crud.inserting.multiple)
+ [更新文件](#cookbook-python.crud.updating)
+ [刪除文件](#cookbook-python.crud.deleting)
+ [在交易中執行多個陳述式](#cookbook-python.crud.multi-statement)
+ [重試邏輯](#cookbook-python.crud.retry-logic)
+ [實作唯一性限制](#cookbook-python.crud.uniqueness-constraints)

### 建立資料表
<a name="cookbook-python.crud.creating-tables"></a>

```
def create_table(transaction_executor):
    transaction_executor.execute_statement("CREATE TABLE Person")

qldb_driver.execute_lambda(lambda executor: create_table(executor))
```

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

```
def create_index(transaction_executor):
    transaction_executor.execute_statement("CREATE INDEX ON Person(GovId)")

qldb_driver.execute_lambda(lambda executor: create_index(executor))
```

### 讀取文件
<a name="cookbook-python.crud.reading"></a>

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

def read_documents(transaction_executor):
    cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'")

    for doc in cursor:
        print(doc["GovId"]) # prints TOYENC486FH
        print(doc["FirstName"]) # prints Brent

qldb_driver.execute_lambda(lambda executor: read_documents(executor))
```

#### 使用查詢參數
<a name="cookbook-python.reading-using-params"></a>

下列程式碼範例使用原生類型查詢參數。

```
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", 'TOYENC486FH')
```

下列程式碼範例使用 Ion 類型查詢參數。

```
name = ion.loads('Brent')
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE FirstName = ?", name)
```

下列程式碼範例使用多個查詢參數。

```
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", 'TOYENC486FH', "Brent")
```

下列程式碼範例使用查詢參數的清單。

```
gov_ids = ['TOYENC486FH','ROEE1','YH844']
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId IN (?,?,?)", *gov_ids)
```

**注意**  
當您在沒有索引查詢的情況下執行查詢時，它會叫用完整的資料表掃描。在此範例中，我們建議在 `GovId` 欄位中具有[索引](ql-reference.create-index.md)，以最佳化效能。如果沒有 上的索引`GovId`，查詢可能會有更多延遲，也可能導致 OCC 衝突例外狀況或交易逾時。

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

下列程式碼範例會插入原生資料類型。

```
def insert_documents(transaction_executor, arg_1):
    # Check if doc with GovId:TOYENC486FH exists
    # This is critical to make this transaction idempotent
    cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", 'TOYENC486FH')
    # Check if there is any record in the cursor
    first_record = next(cursor, None)

    if first_record:
        # Record already exists, no need to insert
        pass
    else:
        transaction_executor.execute_statement("INSERT INTO Person ?", arg_1)

doc_1 = { 'FirstName': "Brent",
          'GovId': 'TOYENC486FH',
        }

qldb_driver.execute_lambda(lambda executor: insert_documents(executor, doc_1))
```

下列程式碼範例會插入 Ion 資料類型。

```
def insert_documents(transaction_executor, arg_1):
    # Check if doc with GovId:TOYENC486FH exists
    # This is critical to make this transaction idempotent
    cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", 'TOYENC486FH')
    # Check if there is any record in the cursor
    first_record = next(cursor, None)

    if first_record:
        # Record already exists, no need to insert
        pass
    else:
        transaction_executor.execute_statement("INSERT INTO Person ?", arg_1)

doc_1 = { 'FirstName': 'Brent',
          'GovId': 'TOYENC486FH',
        }

# create a sample Ion doc
ion_doc_1 = simpleion.loads(simpleion.dumps(doc_1)))

qldb_driver.execute_lambda(lambda executor: insert_documents(executor, ion_doc_1))
```

此交易會將文件插入`Person`資料表。插入之前，它會先檢查文件是否已存在資料表中。**此檢查會讓交易具有等冪性質。**即使您多次執行此交易，也不會造成任何非預期的副作用。

**注意**  
在此範例中，我們建議在 `GovId` 欄位中具有索引，以最佳化效能。如果沒有 上的索引`GovId`，陳述式可能會有更多延遲，也可能導致 OCC 衝突例外狀況或交易逾時。

#### 在一個陳述式中插入多個文件
<a name="cookbook-python.crud.inserting.multiple"></a>

若要使用單一[INSERT](ql-reference.insert.md)陳述式插入多個文件，您可以將類型[清單](driver-working-with-ion.md#driver-ion-list)的參數傳遞至陳述式，如下所示。

```
# people is a list
transaction_executor.execute_statement("INSERT INTO Person ?", people)
```

傳遞清單時，您不會將變數預留位置 (`?`) 括在雙角度括號 ( ) `<<...>>` 中。在手動 PartiQL 陳述式中，雙角括號表示稱為*包*的未排序集合。

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

下列程式碼範例使用原生資料類型。

```
def update_documents(transaction_executor, gov_id, name):
    transaction_executor.execute_statement("UPDATE Person SET FirstName = ?  WHERE GovId = ?", name, gov_id)

gov_id = 'TOYENC486FH'
name = 'John'

qldb_driver.execute_lambda(lambda executor: update_documents(executor, gov_id, name))
```

下列程式碼範例使用 Ion 資料類型。

```
def update_documents(transaction_executor, gov_id, name):
    transaction_executor.execute_statement("UPDATE Person SET FirstName = ? WHERE GovId = ?", name, gov_id)

# Ion datatypes
gov_id = simpleion.loads('TOYENC486FH')
name = simpleion.loads('John')

qldb_driver.execute_lambda(lambda executor: update_documents(executor, gov_id, name))
```

**注意**  
在此範例中，我們建議在 `GovId` 欄位中具有索引，以最佳化效能。如果沒有 上的索引`GovId`，陳述式可能會有更多延遲，也可能導致 OCC 衝突例外狀況或交易逾時。

### 刪除文件
<a name="cookbook-python.crud.deleting"></a>

下列程式碼範例使用原生資料類型。

```
def delete_documents(transaction_executor, gov_id):
    cursor = transaction_executor.execute_statement("DELETE FROM Person WHERE GovId = ?", gov_id)

gov_id = 'TOYENC486FH'

qldb_driver.execute_lambda(lambda executor: delete_documents(executor, gov_id))
```

下列程式碼範例使用 Ion 資料類型。

```
def delete_documents(transaction_executor, gov_id):
    cursor = transaction_executor.execute_statement("DELETE FROM Person WHERE GovId = ?", gov_id)

# Ion datatypes
gov_id = simpleion.loads('TOYENC486FH')

qldb_driver.execute_lambda(lambda executor: delete_documents(executor, gov_id))
```

**注意**  
在此範例中，我們建議在 `GovId` 欄位中具有索引，以最佳化效能。如果沒有 上的索引`GovId`，陳述式可能會有更多延遲，也可能導致 OCC 衝突例外狀況或交易逾時。

### 在交易中執行多個陳述式
<a name="cookbook-python.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.

def do_insure_car(transaction_executor, vin):
    cursor = transaction_executor.execute_statement(
        "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", vin)
    first_record = next(cursor, None)
    if first_record:
        transaction_executor.execute_statement(
            "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", vin)
        return True
    else:
        return False

def insure_car(qldb_driver, vin_to_insure):
    return qldb_driver.execute_lambda(
        lambda executor: do_insure_car(executor, vin_to_insure))
```

### 重試邏輯
<a name="cookbook-python.crud.retry-logic"></a>

驅動程式的 `execute_lambda`方法具有內建重試機制，可在發生可重試例外狀況 （例如逾時或 OCC 衝突） 時重試交易。

------
#### [ 3.x ]

重試嘗試次數上限和退避策略是可設定的。

預設重試限制為 `4`，預設退避策略為[指數退避和抖動](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)，基礎`10`為毫秒。您可以使用 [pyqldb.config.retry\$1config.RetryConfig](https://amazon-qldb-driver-python.readthedocs.io/en/stable/reference/config/retry_config.html#pyqldb.config.retry_config.RetryConfig) 執行個體，設定每個驅動程式執行個體和每個交易的重試組態。

下列程式碼範例指定具有自訂重試限制的重試邏輯，以及驅動程式執行個體的自訂退避策略。

```
from pyqldb.config.retry_config import RetryConfig
from pyqldb.driver.qldb_driver import QldbDriver

# Configuring retry limit to 2
retry_config = RetryConfig(retry_limit=2)
qldb_driver = QldbDriver("test-ledger", retry_config=retry_config)

# Configuring a custom backoff which increases delay by 1s for each attempt.
def custom_backoff(retry_attempt, error, transaction_id):
    return 1000 * retry_attempt

retry_config_custom_backoff = RetryConfig(retry_limit=2, custom_backoff=custom_backoff)
qldb_driver = QldbDriver("test-ledger", retry_config=retry_config_custom_backoff)
```

下列程式碼範例指定具有自訂重試限制的重試邏輯，以及特定 lambda 執行的自訂退避策略。此 組態會`execute_lambda`覆寫為驅動程式執行個體設定的重試邏輯。

```
from pyqldb.config.retry_config import RetryConfig
from pyqldb.driver.qldb_driver import QldbDriver

# Configuring retry limit to 2
retry_config_1 = RetryConfig(retry_limit=4)
qldb_driver = QldbDriver("test-ledger", retry_config=retry_config_1)

# Configuring a custom backoff which increases delay by 1s for each attempt.
def custom_backoff(retry_attempt, error, transaction_id):
    return 1000 * retry_attempt

retry_config_2 = RetryConfig(retry_limit=2, custom_backoff=custom_backoff)

# The config `retry_config_1` will be overriden by `retry_config_2`
qldb_driver.execute_lambda(lambda txn: txn.execute_statement("CREATE TABLE Person"), retry_config_2)
```

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

重試嘗試次數上限為可設定。您可以在初始化 時設定 `retry_limit` 屬性，以設定重試限制`PooledQldbDriver`。

預設重試限制為 `4`。

------

### 實作唯一性限制
<a name="cookbook-python.crud.uniqueness-constraints"></a>

QLDB 不支援唯一索引，但您可以在應用程式中實作此行為。

假設您想要在`Person`資料表中的 `GovId` 欄位實作唯一性限制條件。若要執行此操作，您可以撰寫執行下列動作的交易：

1. 宣告資料表沒有具有指定 的現有文件`GovId`。

1. 如果聲明通過，請插入文件。

如果競爭交易同時通過聲明，則只有一個交易會成功遞交。另一個交易將失敗，並出現 OCC 衝突例外狀況。

下列程式碼範例示範如何實作此唯一性限制邏輯。

```
def insert_documents(transaction_executor, gov_id, document):
    # Check if doc with GovId = gov_id exists
    cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", gov_id)
    # Check if there is any record in the cursor
    first_record = next(cursor, None)

    if first_record:
        # Record already exists, no need to insert
        pass
    else:
        transaction_executor.execute_statement("INSERT INTO Person ?", document)

qldb_driver.execute_lambda(lambda executor: insert_documents(executor, gov_id, document))
```

**注意**  
在此範例中，我們建議在 `GovId` 欄位中具有索引，以最佳化效能。如果沒有 上的索引`GovId`，陳述式可能會有更多延遲，也可能導致 OCC 衝突例外狀況或交易逾時。

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

下列各節說明如何使用 Amazon Ion 模組來處理 Ion 資料。

**Contents**
+ [匯入 Ion 模組](#cookbook-python.ion.import)
+ [建立 Ion 類型](#cookbook-python.ion.creating-types)
+ [取得 Ion 二進位傾印](#cookbook-python.ion.getting-binary)
+ [取得 Ion 文字傾印](#cookbook-python.ion.getting-text)

### 匯入 Ion 模組
<a name="cookbook-python.ion.import"></a>

```
import amazon.ion.simpleion as simpleion
```

### 建立 Ion 類型
<a name="cookbook-python.ion.creating-types"></a>

下列程式碼範例會從 Ion 文字建立 Ion 物件。

```
ion_text = '{GovId: "TOYENC486FH", FirstName: "Brent"}'
ion_obj = simpleion.loads(ion_text)

print(ion_obj['GovId']) # prints TOYENC486FH
print(ion_obj['Name']) # prints Brent
```

下列程式碼範例會從 Python 建立 Ion 物件`dict`。

```
a_dict = { 'GovId': 'TOYENC486FH',
           'FirstName': "Brent"
         }
ion_obj = simpleion.loads(simpleion.dumps(a_dict))

print(ion_obj['GovId']) # prints TOYENC486FH
print(ion_obj['FirstName']) # prints Brent
```

### 取得 Ion 二進位傾印
<a name="cookbook-python.ion.getting-binary"></a>

```
# ion_obj is an Ion struct
print(simpleion.dumps(ion_obj)) # b'\xe0\x01\x00\xea\xee\x97\x81\x83\xde\x93\x87\xbe\x90\x85GovId\x89FirstName\xde\x94\x8a\x8bTOYENC486FH\x8b\x85Brent'
```

### 取得 Ion 文字傾印
<a name="cookbook-python.ion.getting-text"></a>

```
# ion_obj is an Ion struct
print(simpleion.dumps(ion_obj, binary=False)) # prints $ion_1_0 {GovId:'TOYENC486FH',FirstName:"Brent"}
```

如需使用 Ion 的詳細資訊，請參閱 GitHub 上的 [Amazon Ion 文件](http://amzn.github.io/ion-docs/)。如需在 QLDB 中使用 Ion 的更多程式碼範例，請參閱 [在 Amazon QLDB 中使用 Amazon Ion 資料類型](driver-working-with-ion.md)。