Gestionar conexiones con mssql-python

La mayoría de las aplicaciones siguen un patrón sencillo: abrir una conexión, ejecutar consultas, cerrar la conexión. Las siguientes secciones cubren la apertura y cierre de conexiones, el uso de gestores de contexto, la configuración de autocommit y el trabajo con atributos de conexión.

Abre una conexión

Usa la connect() función para establecer una conexión. Proporciona una cadena de conexión con tu servidor, base de datos y datos de autenticación:

import mssql_python

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;Database=<database>;"
    "Authentication=ActiveDirectoryDefault;Encrypt=yes"
)

La connect() función acepta:

  • Una cadena de conexión como primer argumento posicional o la palabra clave connection_str.
  • Palabras clave individuales que el controlador combina en la cadena de conexión.
  • Otras opciones como autocommit, timeout, y attrs_before.

Puedes mezclar ambos enfoques. Las palabras clave invalidan los valores de la cadena de conexión, lo cual resulta útil cuando almacenas una cadena de conexión base en la configuración y sobrescribes opciones como timeout en cada llamada:

# Base connection string from config, with per-call overrides
conn = mssql_python.connect(
    "Server=<server>.database.windows.net;Database=<database>;"
    "Authentication=ActiveDirectoryDefault;Encrypt=yes",
    timeout=30,
    autocommit=True
)

Cerrar una conexión

Cierra siempre las conexiones cuando termines para devolverlas al pool de conexiones y liberar los recursos del servidor. Las conexiones no cerradas almacenan memoria del lado del servidor y pueden agotar eventualmente el conjunto de conexiones, provocando que los intentos de nueva conexión bloqueen o fallen.

conn = mssql_python.connect(connection_string)
try:
    # Use the connection
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
finally:
    conn.close()

Una vez cerrado, la conexión no puede usarse:

conn.close()
print(conn.closed)  # True

# This raises an error
cursor = conn.cursor()  # InterfaceError: Cannot create cursor on closed connection

Llamar a close() múltiples veces es seguro (idempotente):

conn.close()
conn.close()  # No error

Administradores de contexto

Utiliza la with instrucción para gestionar conexiones en la mayoría de las aplicaciones. Garantiza que el controlador cierre la conexión al salir del bloque, incluso si se produce una excepción. Este enfoque elimina el riesgo de fugas de conexiones debido a llamadas olvidadas a close():

with mssql_python.connect(connection_string) as conn:
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE #Demo (Name NVARCHAR(50))")
    cursor.execute("INSERT INTO #Demo (Name) VALUES ('Widget')")
    conn.commit()  # Must commit explicitly when autocommit=False
# Connection automatically closed

El gestor de contexto cierra la conexión al salir. No confirma ni deshace automáticamente las transacciones:

  • Siempre: Llama a close() al salir, se produzca o no una excepción.
  • close() comportamiento: Si autocommit=False, cualquier cambio no comprometido se revierte cuando la conexión se cierra.
  • Debes llamar conn.commit() explícitamente para que los cambios persistan.

Este diseño sigue el comportamiento de PEP 249 y evita confirmaciones parciales accidentales. Si tu código lanza una excepción antes de llegar a commit(), la transacción en curso se revierte de forma segura:

# Equivalent manual code:
conn = mssql_python.connect(connection_string)
try:
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE #Demo (Name NVARCHAR(50))")
    cursor.execute("INSERT INTO #Demo (Name) VALUES ('Widget')")
    conn.commit()  # Must commit explicitly
finally:
    conn.close()  # Rolls back uncommitted changes if autocommit=False

Modo de confirmación automática

Por defecto, autocommit=False, lo que significa que cada instrucción se ejecuta dentro de una transacción implícita. Debes llamar a conn.commit() para guardar los cambios o a conn.rollback() para descartarlos. Las transacciones implícitas son la opción más segura para modificar datos porque permiten agrupar múltiples sentencias en una sola operación atómica.

Activa la confirmación automática si quieres que cada instrucción se confirme inmediatamente. El autocommit es útil para operaciones DDL (CREATE TABLE, ALTER INDEX), cargas de trabajo de solo lectura o scripts administrativos donde no se necesita agrupar transacciones:

conn = mssql_python.connect(connection_string)
print(conn.autocommit)  # False

cursor = conn.cursor()
cursor.execute("CREATE TABLE #Demo (Name NVARCHAR(50))")
cursor.execute("INSERT INTO #Demo (Name) VALUES ('Widget')")
conn.commit()  # Required to persist changes

Activa la confirmación automática para que cada instrucción se confirme inmediatamente. Usa autocommit=True al conectarte, o actívalo o desactívalo después de conectarte con setautocommit() o mediante asignación directa de la propiedad:

# At connection time
conn = mssql_python.connect(connection_string, autocommit=True)

# Or after connection (both forms work)
conn.setautocommit(True)
conn.autocommit = True
print(conn.autocommit)  # True

# Now changes are committed automatically
cursor = conn.cursor()
cursor.execute("SELECT TOP 1 Name FROM Production.Product")
print(cursor.fetchone().Name)
# No commit() needed

Tiempo de espera de conexión

Configura el tiempo de espera de la conexión para controlar cuánto tiempo espera el controlador para establecer la conexión antes de generar un error. Un tiempo de espera razonable de conexión es importante para aplicaciones desplegadas en entornos con redes poco fiables o para fallar rápidamente cuando un servidor es inaccesible:

# At connection time (in seconds)
conn = mssql_python.connect(connection_string, timeout=30)

# Or after connection
conn.timeout = 60
print(conn.timeout)  # 60

Un tiempo de espera de 0 significa que no hay límite de tiempo (espera indefinidamente). Configure tiempos de espera razonables en producción; un intento de conexión bloqueado sin un tiempo de espera configurado bloquea permanentemente el hilo de llamada.

Atributos de conexión

Se usa set_attr() para modificar el comportamiento de la conexión en tiempo de ejecución. Los atributos de conexión controlan configuraciones de controladores de bajo nivel como el modo de acceso, el aislamiento de transacciones y el tamaño del paquete. La mayoría de las aplicaciones no necesitan cambiar estos atributos, pero son útiles para escenarios específicos:

  • Modo de solo lectura: Evita escrituras accidentales en consultas de generación de informes.
  • Aislamiento de transacciones: Controla cómo interactúan las transacciones concurrentes (úsalo SERIALIZABLE para mayor consistencia, READ_COMMITTED para uso general).
  • Tamaño del paquete: Ajusta para redes de alta latencia o de alto rendimiento.
import mssql_python

conn = mssql_python.connect(connection_string)

# Set read-only mode
conn.set_attr(mssql_python.SQL_ATTR_ACCESS_MODE, mssql_python.SQL_MODE_READ_ONLY)

# Set transaction isolation level
conn.set_attr(mssql_python.SQL_ATTR_TXN_ISOLATION, mssql_python.SQL_TXN_SERIALIZABLE)

Atributos disponibles:

Constante Descripción
SQL_ATTR_CONNECTION_TIMEOUT Tiempo de espera de conexión en segundos.
SQL_ATTR_LOGIN_TIMEOUT Tiempo de espera de inicio de sesión en segundos.
SQL_ATTR_PACKET_SIZE Tamaño del paquete de red
SQL_ATTR_ACCESS_MODE Modo de solo lectura o lectura-escritura.
SQL_ATTR_TXN_ISOLATION Nivel de aislamiento de transacciones.
SQL_ATTR_CURRENT_CATALOG Nombre actual de la base de datos.

Atributos de preconexión

Algunos atributos deben establecerse antes de que el controlador establezca la conexión (por ejemplo, el tiempo de espera de inicio de sesión). Pasarlos por attrs_before:

conn = mssql_python.connect(
    connection_string,
    attrs_before={
        mssql_python.SQL_ATTR_LOGIN_TIMEOUT: 30,
        mssql_python.SQL_ATTR_CONNECTION_TIMEOUT: 60,
    }
)

Obtención de información sobre la conexión

Utilizar getinfo() para recuperar metadatos de controladores y servidores para registro, diagnóstico o adaptación de comportamientos según las capacidades del servidor:

conn = mssql_python.connect(connection_string)

# Server information
print(f"Server name: {conn.getinfo(mssql_python.SQL_SERVER_NAME)}")
print(f"Database name: {conn.getinfo(mssql_python.SQL_DATABASE_NAME)}")

# Driver information
print(f"Driver name: {conn.getinfo(mssql_python.SQL_DRIVER_NAME)}")
print(f"Driver version: {conn.getinfo(mssql_python.SQL_DRIVER_VER)}")

Consulta una lista de constantes de información disponibles:

constants = mssql_python.get_info_constants()
for name, value in constants.items():
    print(f"{name}: {value}")

Carácter de escape de búsqueda

La propiedad searchescape devuelve el carácter utilizado para escapar los caracteres comodín (% y _) en los patrones LIKE. Úsalo para buscar de forma segura caracteres comodín de forma literal en la entrada del usuario:

escape = conn.searchescape

# Use in queries with wildcard characters
cursor.execute(
    f"SELECT Name FROM Production.Product WHERE Name LIKE '%{escape}%%' ESCAPE '{escape}'"
)
# Matches names containing literal '%' character

Codificación y descodificación

Configura la codificación de texto para sentencias y resultados SQL. Los ajustes por defecto funcionan para la mayoría de las aplicaciones. Cámbialas solo si te conectas a un servidor que usa una codificación no UTF-8 para char/varchar columnas. La codificación que utiliza un servidor depende de la clasificación de columnas:

# Set encoding for outbound text
conn.setencoding(encoding='utf-8')

# Get current encoding settings
settings = conn.getencoding()
print(settings)  # {'encoding': 'utf-8', 'ctype': ...}

# Set decoding for inbound text from specific SQL types
conn.setdecoding(mssql_python.SQL_CHAR, encoding='utf-8')

# Get current decoding settings
settings = conn.getdecoding(mssql_python.SQL_CHAR)
print(settings)

Codificaciones por defecto:

Dirección Tipo SQL Codificación predeterminada
Saliente (cadena) SQL_WCHAR utf-16le
Entrante SQL_CHAR utf-8
Entrante SQL_WCHAR utf-16le
Entrante SQL_WMETADATA utf-16le

procedimientos recomendados

  • Utiliza gestores de contexto (with bloques) para todas las conexiones en el código de la aplicación. Garantizan la limpieza incluso cuando ocurren excepciones.
  • Usa el pooling de conexiones para mejorar el rendimiento (activado por defecto). Consulta Agrupamiento de conexiones.
  • Establece tiempos de espera apropiados para tu entorno de red. Un tiempo muerto de 30 segundos es adecuado para la mayoría de los despliegues en la nube; aumentarla para conexiones interregionales o VPN.
  • Uso autocommit=False (el predeterminado) para escenarios de modificación de datos donde necesitas atomicidad transaccional.
  • Uso autocommit=True para operaciones DDL, consultas de solo lectura y scripts de administración.
  • No compartas conexiones entre hilos. El nivel de seguridad del driver es 1 (los hilos pueden compartir el módulo pero no las conexiones).