Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
Driver Amazon QLDB per Python — riferimento al ricettario
Questa guida di riferimento mostra i casi d'uso più comuni del driver Amazon QLDB per Python. Fornisce esempi di codice Python che mostrano come utilizzare il driver per eseguire operazioni di creazione, lettura, aggiornamento ed eliminazione (CRUD). Include anche esempi di codice per l'elaborazione dei dati di Amazon Ion. Inoltre, questa guida evidenzia le migliori pratiche per rendere le transazioni idempotenti e implementare i vincoli di unicità.
Nota
Ove applicabile, alcuni casi d'uso hanno esempi di codice diversi per ciascuna versione principale supportata del driver QLDB per Python.
Indice
- Importazione del driver
- Istantizzazione del driver
- Operazioni CRUD
- Uso di Amazon Ion
Importazione del driver
Il seguente esempio di codice importa il driver.
Nota
Questo esempio importa anche il pacchetto Amazon Ion (amazon.ion.simpleion
). È necessario questo pacchetto per elaborare i dati Ion quando si eseguono alcune operazioni sui dati in questo riferimento. Per ulteriori informazioni, consulta Uso di Amazon Ion.
Istantizzazione del driver
L'esempio di codice seguente crea un'istanza del driver che si connette a un nome di registro specificato utilizzando le impostazioni predefinite.
Operazioni CRUD
QLDB esegue operazioni di creazione, lettura, aggiornamento ed eliminazione (CRUD) come parte di una transazione.
avvertimento
Come best practice, cerca di rendere le tue transazioni di scrittura rigorosamente idempotenti.
Rendere le transazioni idempotenti
Ti consigliamo di effettuare transazioni di scrittura idempotenti per evitare effetti collaterali imprevisti in caso di nuovi tentativi. Una transazione è idempotente se può essere eseguita più volte e produrre risultati identici ogni volta.
Ad esempio, si consideri una transazione che inserisce un documento in una tabella denominataPerson
. La transazione deve innanzitutto verificare se il documento esiste già o meno nella tabella. Senza questo controllo, la tabella potrebbe contenere documenti duplicati.
Supponiamo che QLDB esegua correttamente la transazione sul lato server, ma che il client scada in attesa di una risposta. Se la transazione non è idempotente, lo stesso documento potrebbe essere inserito più di una volta in caso di nuovo tentativo.
Utilizzo degli indici per evitare la scansione completa delle tabelle
Si consiglia inoltre di eseguire istruzioni con una clausolaWHERE
predicativa utilizzando un operatore di uguaglianza su un campo indicizzato o un ID di documento, ad esempioWHERE indexedField = 123
oWHERE indexedField IN (456, 789)
. Senza questa ricerca indicizzata, QLDB deve eseguire una scansione della tabella, che può portare a timeout delle transazioni o conflitti OCC (Optimistic Concurrency Control).
Per ulteriori informazioni su OCC, consultaModello di concorrenza Amazon QLDB.
Transazioni create implicitamente
Il metodo pyqldb.driver.qldb_driver.execute_lambdaExecutor
avvolge una transazione creata implicitamente.
È possibile eseguire istruzioni all'interno della funzione lambda utilizzando il metodo execute_statement
Nota
Ilexecute_statement
metodo supporta sia i tipi Amazon Ion che i tipi nativi di Python. Se si passa un tipo nativo di Python come argomentoexecute_statement
, il driver lo converte in un tipo Ion utilizzando ilamazon.ion.simpleion
modulo (a condizione che sia supportata la conversione per il tipo di dati Python specificato). Per i tipi di dati e le regole di conversione supportati, consulta il codice sorgente simpleion
Le sezioni seguenti mostrano come eseguire operazioni CRUD di base, specificare una logica di ripetizione personalizzata e implementare vincoli di unicità.
Indice
Creazione di tabelle
def create_table(transaction_executor): transaction_executor.execute_statement("CREATE TABLE Person") qldb_driver.execute_lambda(lambda executor: create_table(executor))
Creazione di indici
def create_index(transaction_executor): transaction_executor.execute_statement("CREATE INDEX ON Person(GovId)") qldb_driver.execute_lambda(lambda executor: create_index(executor))
Lettura di documenti
# 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))
Utilizzo dei parametri della query
L'esempio di codice seguente utilizza un parametro di interrogazione di tipo nativo.
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", 'TOYENC486FH')
L'esempio di codice seguente utilizza un parametro di interrogazione di tipo Ion.
name = ion.loads('Brent') cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE FirstName = ?", name)
Il seguente esempio di codice utilizza più parametri di interrogazione.
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", 'TOYENC486FH', "Brent")
L'esempio di codice seguente utilizza un elenco di parametri di interrogazione.
gov_ids = ['TOYENC486FH','ROEE1','YH844'] cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId IN (?,?,?)", *gov_ids)
Nota
Quando si esegue una query senza una ricerca indicizzata, viene richiamata una scansione completa della tabella. In questo esempio, consigliamo di avere un indice sulGovId
campo per ottimizzare le prestazioni. Senza un indice attivoGovId
, le query possono avere una maggiore latenza e possono anche portare a eccezioni di conflitto OCC o a timeout delle transazioni.
Inserimento dei documenti
Il seguente esempio di codice inserisce tipi di dati nativi.
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))
Il seguente esempio di codice inserisce i tipi di dati 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))
Questa transazione inserisce un documento nellaPerson
tabella. Prima dell'inserimento, controlla innanzitutto se il documento esiste già nella tabella. Questo controllo rende la transazione di natura idempotente. Anche se esegui questa transazione più volte, non causerà effetti collaterali indesiderati.
Nota
In questo esempio, consigliamo di avere un indice sulGovId
campo per ottimizzare le prestazioni. Senza un indice attivoGovId
, le dichiarazioni possono avere una maggiore latenza e possono anche portare a eccezioni di conflitto OCC o a timeout delle transazioni.
Inserimento di più documenti in un'unica dichiarazione
Per inserire più documenti utilizzando una singolaINSERT istruzione, è possibile passare un elenco di parametri di tipo all'istruzione come segue.
# people is a list transaction_executor.execute_statement("INSERT INTO Person ?", people)
Non si racchiude la variabile placeholder (?
) tra parentesi a doppio angolo (<<...>>
) quando si passa un elenco. Nelle istruzioni PartiQL, le parentesi a doppio angolo indicano una raccolta non ordinata nota come borsa.
Aggiornamento dei documenti
Il seguente esempio di codice utilizza tipi di dati nativi.
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))
Il seguente esempio di codice utilizza i tipi di dati 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))
Nota
In questo esempio, consigliamo di avere un indice sulGovId
campo per ottimizzare le prestazioni. Senza un indice attivoGovId
, le dichiarazioni possono avere una maggiore latenza e possono anche portare a eccezioni di conflitto OCC o a timeout delle transazioni.
Eliminazione di documenti
Il seguente esempio di codice utilizza tipi di dati nativi.
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))
Il seguente esempio di codice utilizza i tipi di dati 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))
Nota
In questo esempio, consigliamo di avere un indice sulGovId
campo per ottimizzare le prestazioni. Senza un indice attivoGovId
, le dichiarazioni possono avere una maggiore latenza e possono anche portare a eccezioni di conflitto OCC o a timeout delle transazioni.
Esecuzione di più rendiconti in una transazione
# 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))
Logica di ripetizione dei tentativi
Ilexecute_lambda
metodo del driver dispone di un meccanismo di ripetizione integrato che riprova la transazione se si verifica un'eccezione ripetibile (ad esempio timeout o conflitti OCC).
Implementazione dei vincoli di unicità
QLDB non supporta indici univoci, ma puoi implementare questo comportamento nella tua applicazione.
Si supponga di voler implementare un vincolo di unicità sulGovId
campo dellaPerson
tabella. Per eseguire questa operazione, è possibile scrivere una transazione che esegue le seguenti operazioni:
-
Asserisci che la tabella non ha documenti esistenti con un valore specificato
GovId
. -
Inserisci il documento se l'asserzione è valida.
Se una transazione concorrente supera contemporaneamente l'asserzione, solo una delle transazioni verrà confermata con successo. L'altra transazione avrà esito negativo con un'eccezione di conflitto OCC.
L'esempio di codice seguente mostra come implementare questa logica di vincolo di unicità.
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))
Nota
In questo esempio, consigliamo di avere un indice sulGovId
campo per ottimizzare le prestazioni. Senza un indice attivoGovId
, le dichiarazioni possono avere una maggiore latenza e possono anche portare a eccezioni di conflitto OCC o a timeout delle transazioni.
Uso di Amazon Ion
Le sezioni seguenti mostrano come utilizzare il modulo Amazon Ion per elaborare i dati Ion.
Indice
Importazione del modulo Ion
import amazon.ion.simpleion as simpleion
Creazione di tipi di ioni
Il seguente esempio di codice crea un oggetto Ion dal testo 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
Il seguente esempio di codice crea un oggetto Ion da un Pythondict
.
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
Ottenere un dump binario Ion
# 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'
Ottenere un dump di testo Ion
# ion_obj is an Ion struct print(simpleion.dumps(ion_obj, binary=False)) # prints $ion_1_0 {GovId:'TOYENC486FH',FirstName:"Brent"}
Per ulteriori informazioni sull'utilizzo di Ion, consulta la documentazione di Amazon Ion