Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Controlador Amazon QLDB para Python: referencia de libro de cocina
Esta guía de referencia muestra casos de uso comunes del controlador Amazon QLDB para Python. Proporciona ejemplos de código de Python que demuestran cómo usar el controlador para ejecutar operaciones básicas de creación, lectura, actualización y eliminación (CRUD). También incluye ejemplos de código para procesar datos de Amazon Ion. Además, esta guía destaca las mejores prácticas para hacer que las transacciones sean idempotentes e implementar restricciones de unicidad.
Cuando proceda, algunos casos de uso tienen diferentes ejemplos de código para cada versión principal compatible del controlador QLDB para Python.
Contenido
- Importación del controlador
- Creación de una instancia del controlador
- Operaciones CRUD
- Trabajo con Amazon Ion
Importación del controlador
El siguiente ejemplo de código importa el controlador.
En este ejemplo también se importa el paquete Amazon Ion (amazon.ion.simpleion
). Necesita este paquete para procesar los datos de Ion al ejecutar algunas operaciones de datos en esta referencia. Para obtener más información, consulte Trabajo con Amazon Ion.
Creación de una instancia del controlador
El siguiente ejemplo de código crea una instancia del controlador que se conecta a un nombre de registro especificado mediante la configuración predeterminada.
Operaciones CRUD
QLDB ejecuta operaciones de creación, lectura, actualización y eliminación (CRUD) como parte de una transacción.
Como práctica recomendada, haga que sus transacciones de escritura sean estrictamente idempotentes.
Hacer que las transacciones sean idempotentes
Le recomendamos que haga que las transacciones de escritura sean idempotentes para evitar efectos secundarios inesperados en caso de reintentos. Una transacción es idempotente si puede ejecutarse varias veces y producir resultados idénticos cada vez.
Por ejemplo, considere una transacción que inserta un documento en una tabla denominadaPerson
. La transacción debe comprobar primero si el documento ya existe o no en la tabla. Sin esta comprobación, la tabla podría terminar con documentos duplicados.
Supongamos que QLDB confirma correctamente la transacción en el servidor, pero el cliente agota el tiempo de espera mientras espera una respuesta. Si la transacción no es idempotente, se puede insertar el mismo documento más de una vez en caso de que se vuelva a intentar.
Uso de índices para evitar escaneos de tablas completas
También le recomendamos que ejecute sentencias con una cláusula deWHERE
predicados mediante un operador de igualdad en un campo indexado o un ID de documento; por ejemplo,WHERE indexedField = 123
oWHERE indexedField IN (456, 789)
. Sin esta búsqueda indexada, QLDB necesita realizar un escaneo de tablas, lo que puede provocar tiempos de espera de las transacciones o conflictos optimistas en el control de la concurrencia (OCC).
Para obtener más información sobre la OCC, consulteModelo de simultaneidad de Amazon QLDB.
Transacciones creadas implícitamente
El método pyqldb.driver.qldb_driver.execute_lambdaExecutor
envuelve una transacción creada de forma implícita.
Puede ejecutar sentencias dentro de la función lambda mediante el método execute_statement
Elexecute_statement
método admite los tipos de Amazon Ion y los tipos nativos de Python. Si pasas un tipo nativo de Python como argumento aexecute_statement
, el controlador lo convierte en un tipo Ion mediante elamazon.ion.simpleion
módulo (siempre que se admita la conversión para el tipo de datos de Python dado). Para conocer los tipos de datos y las reglas de conversión compatibles, consulte el código fuente de simpleion
En las siguientes secciones se muestra cómo ejecutar operaciones CRUD básicas, especificar una lógica de reintentos personalizada e implementar restricciones de unicidad.
Contenido
Creación de tablas
def create_table(transaction_executor): transaction_executor.execute_statement("CREATE TABLE Person") qldb_driver.execute_lambda(lambda executor: create_table(executor))
Creación de índice
def create_index(transaction_executor): transaction_executor.execute_statement("CREATE INDEX ON Person(GovId)") qldb_driver.execute_lambda(lambda executor: create_index(executor))
Lectura de documentos
# 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))
Uso de parámetros de consulta
El siguiente ejemplo de código utiliza un parámetro de consulta de tipo nativo.
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ?", 'TOYENC486FH')
El siguiente ejemplo de código utiliza un parámetro de consulta de tipo Ion.
name = ion.loads('Brent') cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE FirstName = ?", name)
El siguiente ejemplo de código utiliza varios parámetros de consulta.
cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", 'TOYENC486FH', "Brent")
El siguiente ejemplo de código utiliza una lista de parámetros de consulta.
gov_ids = ['TOYENC486FH','ROEE1','YH844'] cursor = transaction_executor.execute_statement("SELECT * FROM Person WHERE GovId IN (?,?,?)", *gov_ids)
Cuando se ejecuta una consulta sin una búsqueda indexada, se invoca un escaneo completo de la tabla. En este ejemplo, recomendamos tener un índice en elGovId
campo para optimizar el rendimiento. Sin un índice activadoGovId
, las consultas pueden tener más latencia y también provocar excepciones de conflictos de OCC o tiempos de espera para las transacciones.
Inserción de documentos
El siguiente ejemplo de código inserta tipos de datos nativos.
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))
En el siguiente ejemplo de código se insertan tipos de datos de iones.
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))
Esta transacción inserta un documento en laPerson
tabla. Antes de insertarlo, comprueba primero si el documento ya existe en la tabla. Esta comprobación hace que la transacción sea de naturaleza idempotente. Incluso si realizas esta transacción varias veces, no causará ningún efecto secundario no deseado.
En este ejemplo, recomendamos tener un índice en elGovId
campo para optimizar el rendimiento. Sin un índice activadoGovId
, las declaraciones pueden tener más latencia y también pueden provocar excepciones de conflictos de OCC o tiempos de espera para las transacciones.
Insertar varios documentos en una declaración
Para insertar varios documentos mediante una solaINSERT sentencia, puede pasar un parámetro de tipo lista a la sentencia de la siguiente manera.
# people is a list transaction_executor.execute_statement("INSERT INTO Person ?", people)
No debe incluir el marcador de posición variable (?
) entre corchetes de doble ángulo (<<...>>
) al pasar una lista. En las sentencias PartiQL manuales, los corchetes de doble ángulo indican una colección desordenada conocida como bolsa.
Actualización de documentos
El siguiente ejemplo de código utiliza tipos de datos nativos.
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))
El siguiente ejemplo de código utiliza tipos de datos de iones.
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))
En este ejemplo, recomendamos tener un índice en elGovId
campo para optimizar el rendimiento. Sin un índice activadoGovId
, las declaraciones pueden tener más latencia y también pueden provocar excepciones de conflictos de OCC o tiempos de espera para las transacciones.
Eliminación de documentos
El siguiente ejemplo de código utiliza tipos de datos nativos.
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))
El siguiente ejemplo de código utiliza tipos de datos de iones.
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))
En este ejemplo, recomendamos tener un índice en elGovId
campo para optimizar el rendimiento. Sin un índice activadoGovId
, las declaraciones pueden tener más latencia y también pueden provocar excepciones de conflictos de OCC o tiempos de espera para las transacciones.
Ejecutar varios estados de cuenta en una transacción
# 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))
Reintentar la lógica
Elexecute_lambda
método del conductor tiene un mecanismo de reintento incorporado que reintenta la transacción si se produce una excepción que se puede volver a intentar (como tiempos de espera o conflictos de OCC).
Implementación de restricciones de unicidad
QLDB no admite índices únicos, pero puede implementar este comportamiento en su aplicación.
Supongamos que desea implementar una restricción de unicidad en elGovId
campo de laPerson
tabla. Para ello, puede escribir una transacción que haga lo siguiente:
-
Afirma que la tabla no tiene ningún documento existente con una especificada
GovId
. -
Inserte el documento si la afirmación es aprobada.
Si una transacción competidora supera la afirmación simultáneamente, solo una de las transacciones se confirmará satisfactoriamente. La otra transacción fallará si se produce una excepción de conflicto de OCC.
En el ejemplo de código siguiente se muestra cómo implementar esta lógica de restricción de unicidad.
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))
En este ejemplo, recomendamos tener un índice en elGovId
campo para optimizar el rendimiento. Sin un índice activadoGovId
, las declaraciones pueden tener más latencia y también pueden provocar excepciones de conflictos de OCC o tiempos de espera para las transacciones.
Trabajo con Amazon Ion
Las siguientes secciones muestran cómo usar el módulo Amazon Ion para procesar datos de Ion.
Contenido
Importación del módulo Ion
import amazon.ion.simpleion as simpleion
Creación de tipos de Ion
El siguiente ejemplo de código crea un objeto Ion a partir del texto de 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
El siguiente ejemplo de código crea un objeto Ion a partir de 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
Obtener un volcado binario de iones
# 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'
Obtener un volcado de texto de Ion
# ion_obj is an Ion struct print(simpleion.dumps(ion_obj, binary=False)) # prints $ion_1_0 {GovId:'TOYENC486FH',FirstName:"Brent"}
Para obtener más información sobre cómo trabajar con Ion, consulte la documentación de Amazon Ion