Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Amazon QLDB-Treiber für Python — Kochbuch-Referenz
Dieses Referenzhandbuch zeigt häufige Anwendungsfälle des Amazon QLDB-Treibers für Python. Es enthält Pyon-Codebeispiele, die zeigen, wie CRUD-Operationen (Erstellen, Lesen, Aktualisieren, Löschen) ausführen. Es enthält auch Codebeispiele für die Verarbeitung von Amazon Ion-Daten. Darüber hinaus werden in diesem Leitfaden bewährte Verfahren vorgestellt, um Transaktionen idempotent zu machen und Eindeutigkeitsbeschränkungen zu implementieren.
Anmerkung
Gegebenenfalls haben einige Anwendungsfälle unterschiedliche Codebeispiele für jede unterstützte Hauptversion des QLDB-Treibers für Python.
Inhalt
- Importieren des Treibers
- instanziieren des Treibers
- CRUD-Operationen
- Arbeiten mit Amazon Ion-Technologie
Importieren des Treibers
Das folgende Codebeispiel importiert den Treiber.
Anmerkung
In diesem Beispiel wird auch das Amazon Ion-Paket (amazon.ion.simpleion
) importiert. Sie benötigen dieses Paket, um Ion-Daten zu verarbeiten, wenn Sie einige Datenoperationen in dieser Referenz ausführen. Weitere Informationen hierzu finden Sie unter Arbeiten mit Amazon Ion-Technologie.
instanziieren des Treibers
Das folgende Codebeispiel erstellt eine Instanz des Treibers, die mithilfe der Standardeinstellungen eine Verbindung zu einem angegebenen Ledger-Namen herstellt.
CRUD-Operationen
QLDB führt CRUD-Operationen (Erstellen, Lesen, Aktualisieren, Löschen) als Teil einer Transaktion durch.
Warnung
Als bewährte Methode sollten Schreibtransaktionen strikt idempotent sein.
Transaktionen idempotent machen
Wir empfehlen, Schreibtransaktionen idempotent zu machen, um unerwartete Nebenwirkungen bei Wiederholungsversuchen zu vermeiden. Eine Transaktion ist idempotent, wenn sie mehrfach ausgeführt werden kann und jedes Mal zu identischen Ergebnissen führt.
Stellen Sie sich zum Beispiel eine Transaktion vor, bei der ein Dokument in eine Tabelle mit dem Namen eingefügt wirdPerson
. Die Transaktion sollte zunächst prüfen, ob das Dokument bereits in der Tabelle vorhanden ist. Ohne diese Überprüfung enthält die Tabelle möglicherweise doppelte Dokumente.
Nehmen wir an, QLDB führt die Transaktion auf der Serverseite erfolgreich durch, aber der Client läuft beim Warten auf eine Antwort ein Timeout. Wenn die Transaktion nicht idempotent ist, kann dasselbe Dokument im Falle eines erneuten Versuchs mehrmals eingefügt werden.
Verwendung von Indizes zur Vermeidung vollständiger Tabellenscans
Wir empfehlen außerdem, Anweisungen mit einerWHERE
Prädikatklausel auszuführen, indem Sie einen Gleichheitsoperator für ein indiziertes Feld oder eine Dokument-ID verwenden, z. B.WHERE indexedField = 123
oderWHERE indexedField IN (456, 789)
. Ohne diese indizierte Suche muss QLDB einen Tabellenscan durchführen, was zu Transaktions-Timeouts oder OCC-Konflikten (Optimist Concurrency Control) führen kann.
Weitere Informationen zu OCC finden Sie unter Amazon QLDB-Nebenläufigkeit von Amazon QLDB-Nebenläufigkeit.
Implizit erstellte Transaktionen
Die Methode pyqldb.driver.qldb_driver.execute_lambdaExecutor
umschließt eine implizit erstellte Transaktion.
Sie können Anweisungen innerhalb der Lambda-Funktion ausführen, indem Sie die Methode execute_statement
Anmerkung
Dieexecute_statement
Methode unterstützt sowohl Amazon Ion-Typen als auch native Python-Typen. Wenn Sie einen nativen Python-Typ als Argument an übergebenexecute_statement
, konvertiert der Treiber ihn mithilfe desamazon.ion.simpleion
Moduls in einen Ion-Typ (vorausgesetzt, dass die Konvertierung für den angegebenen Python-Datentyp unterstützt wird). Unterstützte Datentypen und Konvertierungsregeln finden Sie im Simpleion-Quellcode
In den folgenden Abschnitten wird gezeigt, wie grundlegende CRUD-Operationen ausgeführt, eine benutzerdefinierte Wiederholungslogik angegeben und Eindeutigkeitsbeschränkungen implementiert werden.
Inhalt
Erstellen von Tabellen
def create_table(transaction_executor): transaction_executor.execute_statement("CREATE TABLE Person") qldb_driver.execute_lambda(lambda executor: create_table(executor))
Erstellen von Indizes
def create_index(transaction_executor): transaction_executor.execute_statement("CREATE INDEX ON Person(GovId)") qldb_driver.execute_lambda(lambda executor: create_index(executor))
Dokumente lesen
# 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))
Verwenden von Abfrageparametern
Das folgende Codebeispiel verwendet einen Abfrageparameter vom systemeigenen Typ.
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", 'TOYENC486FH')
Das folgende Codebeispiel verwendet einen Abfrageparameter vom Typ Ion.
name = ion.loads('Brent') cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE FirstName = ?", name)
Das folgende Codebeispiel verwendet mehrere Abfrageparameter.
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", 'TOYENC486FH', "Brent")
Das folgende Codebeispiel verwendet eine Liste von Abfrageparametern.
gov_ids = ['TOYENC486FH','ROEE1','YH844'] cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId IN (?,?,?)", *gov_ids)
Anmerkung
Wenn Sie eine Abfrage ohne eine indizierte Suche ausführen, wird ein vollständiger Tabellenscan aufgerufen. In diesem Beispiel empfehlen wir, einen Index für dasGovId
Feld zu haben, um die Leistung zu optimieren. Ohne aktiviertenGovId
Index können Abfragen mehr Latenz haben und auch zu OCC-Konfliktausnahmen oder Transaktions-Timeouts führen.
Einfügen von Dokumenten
Das folgende Codebeispiel fügt native Datentypen ein.
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))
Das folgende Codebeispiel fügt Ion-Datentypen ein.
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))
Diese Transaktion fügt ein Dokument in diePerson
Tabelle ein. Vor dem Einfügen wird zunächst geprüft, ob das Dokument bereits in der Tabelle vorhanden ist. Diese Prüfung macht die Transaktion idempotenter Natur. Selbst wenn Sie diese Transaktion mehrmals ausführen, verursacht sie keine unbeabsichtigten Nebenwirkungen.
Anmerkung
In diesem Beispiel empfehlen wir, einen Index für dasGovId
Feld zu haben, um die Leistung zu optimieren. Ohne aktiviertenGovId
Index können Anweisungen mehr Latenz haben und auch zu OCC-Konfliktausnahmen oder Transaktions-Timeouts führen.
Einfügen mehrerer Dokumente in eine Anweisung
Um mehrere Dokumente mit einer einzigenINSERT Anweisung einzufügen, können Sie wie folgt einen Parameter vom Typ list an die Anweisung übergeben.
# people is a list transaction_executor.execute_statement("INSERT INTO Person ?", people)
Sie schließen den variablen Platzhalter (?
) nicht in doppelte eckige Klammern (<<...>>
) ein, wenn Sie eine Liste übergeben. In manuellen PartiQL-Anweisungen bezeichnen doppelte spitze Klammern eine ungeordnete Sammlung, die als Bag bezeichnet wird.
Dokumente aktualisieren
Das folgende Codebeispiel verwendet native Datentypen.
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))
Das folgende Codebeispiel verwendet Ion-Datentypen.
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))
Anmerkung
In diesem Beispiel empfehlen wir, einen Index für dasGovId
Feld zu haben, um die Leistung zu optimieren. Ohne aktiviertenGovId
Index können Anweisungen mehr Latenz haben und auch zu OCC-Konfliktausnahmen oder Transaktions-Timeouts führen.
Dokumente löschen
Das folgende Codebeispiel verwendet native Datentypen.
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))
Das folgende Codebeispiel verwendet Ion-Datentypen.
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))
Anmerkung
In diesem Beispiel empfehlen wir, einen Index für dasGovId
Feld zu haben, um die Leistung zu optimieren. Ohne aktiviertenGovId
Index können Anweisungen mehr Latenz haben und auch zu OCC-Konfliktausnahmen oder Transaktions-Timeouts führen.
Ausführen mehrerer Kontoauszüge in einer Transaktion
# 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))
Wiederholungslogik
Dieexecute_lambda
Methode des Treibers verfügt über einen integrierten Wiederholungsmechanismus, der die Transaktion erneut versucht, wenn eine wiederholbare Ausnahme auftritt (z. B. Timeouts oder OCC-Konflikte).
Implementierung von Eindeutigkeitseinschränkungen
QLDB unterstützt keine eindeutigen Indizes, aber Sie können dieses Verhalten in Ihrer Anwendung implementieren.
Angenommen, Sie möchten eine Eindeutigkeitsbeschränkung für dasGovId
Feld in derPerson
Tabelle implementieren. Dazu können Sie eine Transaktion schreiben, die Folgendes bewirkt:
-
Stellen Sie sicher, dass die Tabelle keine vorhandenen Dokumente mit einem bestimmten Wert enthält
GovId
. -
Fügen Sie das Dokument ein, wenn die Assertion erfolgreich ist.
Besteht eine konkurrierende Transaktion gleichzeitig die Assertion, wird nur eine der Transaktionen erfolgreich abgeschlossen. Die andere Transaktion schlägt mit einer OCC-Konfliktexception fehl.
Das folgende Codebeispiel veranschaulicht, wie diese Logik für Eindeutigkeitseinschränkungen implementiert wird.
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))
Anmerkung
In diesem Beispiel empfehlen wir, einen Index für dasGovId
Feld zu haben, um die Leistung zu optimieren. Ohne aktiviertenGovId
Index können Anweisungen mehr Latenz haben und auch zu OCC-Konfliktausnahmen oder Transaktions-Timeouts führen.
Arbeiten mit Amazon Ion-Technologie
In den folgenden Abschnitten sehen Sie, wie das Amazon-Ion-Modul für die Verarbeitung von Ion-Daten verwendet werden.
Inhalt
Import des Ionen-Moduls
import amazon.ion.simpleion as simpleion
Erstellen von Ion-Typen
Das folgende Codebeispiel erstellt ein Ion-Objekt aus Ion-Text.
ion_text = '{GovId: "TOYENC486FH", FirstName: "Brent"}' ion_obj = simpleion.loads(ion_text) print(ion_obj['GovId']) # prints TOYENC486FH print(ion_obj['Name']) # prints Brent
Das folgende Codebeispiel erstellt ein Ion-Objekt aus einem 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
Einen Ion-Binärdump abrufen
# 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'
Einen Ion-Textdump abrufen
# ion_obj is an Ion struct print(simpleion.dumps(ion_obj, binary=False)) # prints $ion_1_0 {GovId:'TOYENC486FH',FirstName:"Brent"}
Weitere Informationen zur Arbeit mit Ion finden Sie in der Amazon Ion-Dokumentation