Integración de SDK y aplicaciones
La integración de Azure Database for PostgreSQL en las aplicaciones requiere elegir las bibliotecas cliente adecuadas, administrar las conexiones de forma eficaz y controlar los errores correctamente. En esta unidad se tratan los patrones de integración del SDK para Python, junto con los procedimientos recomendados que se aplican a través de lenguajes de programación.
Nota:
En los ejemplos de código de esta unidad se muestran patrones para integrar PostgreSQL con las aplicaciones. La psycopg biblioteca se actualiza con frecuencia. Visite la documentación de psycopg para obtener los detalles más actuales de la API y los procedimientos recomendados.
Integración de Python con psycopg
La psycopg biblioteca (versión 3) es el adaptador de PostgreSQL recomendado para Python. Proporciona interfaces sincrónicas y asincrónicas, agrupación de conexiones y compatibilidad completa con las características de PostgreSQL.
Instale psycopg mediante pip con el archivo binario adicional para que la configuración sea más sencilla: pip install "psycopg[binary]". La distribución binaria incluye dependencias precompiladas, lo que evita la necesidad de instalar bibliotecas cliente de PostgreSQL en la máquina de desarrollo. En el caso de las implementaciones de producción en las que es necesario compilar en bibliotecas cliente de PostgreSQL específicas, instale sin el binario adicional y asegúrese de que libpq los encabezados de desarrollo estén disponibles.
Cree conexiones con psycopg.connect() con una cadena de conexión o con parámetros individuales. Las cadenas de conexión son cómodas para los archivos de configuración, mientras que los parámetros individuales ofrecen flexibilidad para calcular valores mediante programación, como la recuperación de contraseñas de Key Vault:
import psycopg
# Connection string format
conn = psycopg.connect("postgresql://user:password@myserver.postgres.database.azure.com/mydb?sslmode=require")
# Individual parameters
conn = psycopg.connect(host="myserver.postgres.database.azure.com", dbname="mydb",
user="myuser", password="mypassword", sslmode="require")
Los administradores de contexto garantizan que las conexiones están cerradas correctamente, incluso cuando se producen excepciones. El bloque externo with administra la conexión y el bloque interno with administra el cursor:
with psycopg.connect(connection_string) as conn:
with conn.cursor() as cur:
cur.execute("SELECT * FROM conversations WHERE id = %s", (conversation_id,))
row = cur.fetchone()
Use siempre consultas con parámetros para evitar ataques por inyección de código SQL. Las consultas parametrizadas separan la estructura SQL de los valores de los datos, lo que permite que el controlador de la base de datos se encargue de neutralizar (escapar) los caracteres especiales de forma adecuada. Use %s marcadores de posición para parámetros posicionales o %(name)s para parámetros con nombre. Nunca use el formato de cadena ni la concatenación para crear consultas con la entrada del usuario.
Recupere los resultados de la consulta mediante métodos de cursor que coincidan con sus necesidades. Utilice fetchone() cuando espere una sola fila, fetchall() para conjuntos de resultados pequeños e itere directamente sobre el cursor para resultados grandes para evitar cargar todo en la memoria al mismo tiempo.
Procedimientos recomendados de administración de conexiones
La administración eficaz de conexiones mejora la confiabilidad y el rendimiento de las aplicaciones independientemente del lenguaje de programación que use.
Establezca los tiempos de espera adecuados para evitar que la aplicación se bloquee cuando la base de datos no sea accesible o las consultas se ejecuten más de lo esperado. Los tiempos de espera de conexión controlan cuánto tiempo espera el cliente para establecer una conexión, mientras que los tiempos de espera de instrucciones limitan el tiempo de ejecución de la consulta. Elija valores de tiempo de espera en función de la tolerancia de la aplicación a la latencia: las aplicaciones web suelen usar tiempos de espera más cortos (cinco a 30 segundos) que los trabajos de procesamiento por lotes.
conn = psycopg.connect(
connection_string,
connect_timeout=10,
options="-c statement_timeout=30000" # milliseconds
)
Implemente la lógica de reintento con retroceso exponencial para controlar errores transitorios de problemas de red, reinicios del servidor o contención de recursos. Detecte OperationalError en caso de errores de conexión y tiempos de espera. No vuelva a intentar en caso de infracciones de restricciones o errores de sintaxis, ya que estos requieren cambios en el código, no reintentos.
Cierre siempre las conexiones cuando haya terminado con ellas. Las conexiones filtradas agotan el grupo de conexiones y pueden evitar nuevas conexiones. Los administradores de contexto proporcionan una limpieza automática que funciona incluso cuando se producen excepciones.
Estrategias de control de errores
Las operaciones de base de datos pueden producir errores por diversos motivos. El manejo adecuado de los errores mejora la experiencia del usuario y simplifica la depuración.
Los errores de conexión se producen cuando el servidor no es accesible o rechaza la conexión: pueden producirse problemas de red, credenciales incorrectas, reglas de firewall o mantenimiento del servidor. Maneje los errores de conexión registrando los detalles para la resolución de problemas mientras presenta mensajes amigables para los usuarios finales.
Las restricciones únicas, las claves externas y las restricciones check generan errores específicos cuando se infringen. Detecte UniqueViolation, ForeignKeyViolation y CheckViolation para incluir comentarios importantes. Siempre revierte la transacción después de una violación de una restricción.
Los interbloqueos se producen cuando dos transacciones esperan los bloqueos del otro, creando una dependencia circular. PostgreSQL detecta automáticamente interbloqueos y finaliza una transacción. La aplicación debe detectar DeadlockDetected, revertir y reintentar. Para minimizar el riesgo de interbloqueo, diseñe las transacciones para adquirir los bloqueos en un orden coherente. Controle LockNotAvailable de manera similar cuando las consultas superen el tiempo de espera por bloqueos.
Consideraciones sobre el rendimiento
Los patrones de nivel de aplicación pueden afectar significativamente al rendimiento de la base de datos.
Inserte varias filas en una sola instrucción en lugar de ejecutar inserciones individuales en un bucle. Las operaciones por lotes reducen los recorridos de ida y vuelta de red, lo que mejora significativamente el rendimiento de las operaciones masivas de datos. Se usa executemany para insertar desde cientos hasta unos pocos miles de filas. Para conjuntos de datos más grandes (más de 10 000 filas), el COPY comando proporciona el rendimiento más alto, a menudo de dos a 10 veces más rápido que las inserciones individuales:
with cur.copy("COPY messages (conversation_id, role, content) FROM STDIN") as copy:
for record in records:
copy.write_row(record)
Las instrucciones preparadas pueden mejorar el rendimiento de las consultas ejecutadas repetidamente con distintos parámetros. La base de datos analiza y planea la consulta una vez y, a continuación, reutiliza ese plan. La mayoría de los controladores de PostgreSQL usan automáticamente instrucciones preparadas para consultas con parámetros.
La creación de nuevas conexiones de base de datos es costosa: cada una requiere protocolos de enlace de red, autenticación y asignación de recursos del lado servidor. Usa grupos de conexiones para mantener conexiones reutilizables que tu aplicación pueda tomar prestadas y devolver.
from psycopg_pool import ConnectionPool
pool = ConnectionPool(connection_string, min_size=1, max_size=10)
with pool.connection() as conn:
with conn.cursor() as cur:
cur.execute("SELECT * FROM messages WHERE conversation_id = %s", (id,))