

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Python용 Amazon QLDB 드라이버
<a name="getting-started.python"></a>

**중요**  
지원 종료 알림: 기존 고객은 07/31/2025에 지원이 종료될 때까지 Amazon QLDB를 사용할 수 있습니다. 자세한 내용은 [Amazon QLDB 원장을 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)
+ [Cookbook 참조](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 다운로드](https://www.python.org/downloads/) 사이트에서 다음 버전의 Python 중 하나를 설치합니다.
   + **3.6 이상** - Python v3용 QLDB 드라이버
   + **3.4 이상** - Python v2용 QLDB 드라이버

1.  AWS 자격 증명과 기본값을 설정합니다 AWS 리전. 지침은 AWS SDK for Python (Boto3) 설명서의 [Quickstart](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration)를 참조하세요.

   사용 가능한 리전의 전체 목록은 *AWS 일반 참조*에서 [Amazon QLDB 엔드포인트 및 할당량](https://docs.aws.amazon.com/general/latest/gr/qldb.html)을 참조하세요.

다음으로 전체 자습서 샘플 애플리케이션을 다운로드하거나 Python 프로젝트에 드라이버만 설치하고 단축 코드 예제를 실행할 수 있습니다.
+ 기존 프로젝트에 QLDB 드라이버와 AWS SDK for Python (Boto3) 를 설치하려면 로 이동합니다[설치](#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 버전 | 상태 표시기 | 최근 릴리스 날짜 | 
| --- | --- | --- | --- | 
| [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
```

------

드라이버를 설치하면 [AWS SDK for Python (Boto3)](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)
```

------

원장에서 기본 데이터 트랜잭션을 실행하는 방법에 대한 단축 코드 예제는 [Cookbook 참조](driver-cookbook-python.md)를 참조하세요.

# Python용 Amazon QLDB 드라이버 - 빠른 시작 자습서
<a name="driver-quickstart-python"></a>

**중요**  
지원 종료 공지: 기존 고객은 07/31/2025에 지원이 종료될 때까지 Amazon QLDB를 사용할 수 있습니다. 자세한 내용은 [Amazon QLDB 원장을 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`라는 명칭의 원장을 생성합니다.

   원장 생성 방법을 알아보려면 *콘솔 시작하기*의 [Amazon QLDB 원장의 기본 작업](ledger-management.basics.md) 또는 [1단계: 새 원장 생성](getting-started-step-1.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
   ```

   드라이버를 설치하면 [AWS SDK for Python (Boto3)](https://aws.amazon.com/sdk-for-net) 및 [Amazon Ion](ion.md) 패키지를 포함한 해당 종속 항목도 설치됩니다.

1. `app.py`라는 명칭의 새로운 파일을 만듭니다.

   그런 다음, 다음 단계의 코드 예를 점진적으로 추가하여 몇 가지 기본 CRUD 작업을 시도해 보세요. 또는 단계별 자습서를 건너뛰고 [전체 애플리케이션](#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` 문을 실행하는 방법을 보여줍니다.

`People`라는 명칭의 표와 해당 표의 `lastName` 필드 인덱스를 만드는 다음 코드를 추가합니다. [인덱스](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`를 `42`로 업데이트하여 `People` 표의 문서를 업데이트하는 다음 코드를 추가합니다.

   ```
   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` 애플리케이션의 전체 버전입니다. 이전 단계를 개별적으로 수행하는 대신 이 코드 예를 처음부터 끝까지 복사하여 실행할 수도 있습니다. 이 애플리케이션은 `quick-start`이라는 명칭의 원장에 대한 몇 가지 기본 CRUD 작업을 보여줍니다.

**참고**  
이 코드를 실행하기 전에 `quick-start` 원장에 `People`이라는 명칭의 활성 테이블이 아직 없는지 확인하세요.

```
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 드라이버 - Cookbook 참조
<a name="driver-cookbook-python"></a>

**중요**  
지원 종료 알림: 기존 고객은 07/31/2025에 지원이 종료될 때까지 Amazon QLDB를 사용할 수 있습니다. 자세한 내용은 [Amazon QLDB 원장을 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 indexedField = 123` 또는 `WHERE indexedField IN (456, 789)`)에서 동등 *연산자*를 사용하여 `WHERE` 조건자 절이 포함된 문을 실행하는 것이 좋습니다. 이 인덱싱된 조회가 없으면 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) 메서드는 [pyqldb.execution.executor.Executor](https://amazon-qldb-driver-python.readthedocs.io/en/stable/reference/execution/executor.html#pyqldb.execution.executor.Executor)의 인스턴스를 수신하는 Lambda 함수를 받아들이며, 이 함수를 사용하여 명령문을 실행할 수 있습니다. `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 데이터 유형에 대한 변환이 지원되는 경우). 지원되는 데이터 유형 및 변환 규칙은 [simpleion 소스 코드](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`이며, 기본 백오프 전략은 `10`밀리초 단위의 [지수 백오프 및 Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)입니다. [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 ]

최대 재시도 횟수는 구성 가능합니다. `PooledQldbDriver`를 초기화할 때 `retry_limit` 속성을 설정하여 재시도 제한을 구성할 수 있습니다.

기본 재시도 한도는 `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 `dict`에서 Ion 객체를 만듭니다.

```
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) 섹션을 참조하세요.