Gerir ligações com mssql-python

A maioria das aplicações segue um padrão simples: abrir uma ligação, executar consultas, fechar a ligação. As secções seguintes abordam a abertura e o encerramento de ligações, utilização de gestores de contexto, configuração do autocommit e trabalho com atributos de ligação.

Abrir uma ligação

Use a connect() função para estabelecer uma ligação. Passe uma cadeia de ligação com o seu servidor, base de dados e detalhes de autenticação:

import mssql_python

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

A connect() função aceita:

  • Uma cadeia de ligação como primeiro argumento posicional ou a palavra-chave connection_str.
  • Palavras-chave individuais que o controlador combina na cadeia de ligação.
  • Outras opções como autocommit, timeout, e attrs_before.

Podes misturar ambas as abordagens. As palavras-chave substituem os valores na cadeia de ligação, o que é útil quando armazena uma cadeia de ligação de base na configuração e substitui definições como timeout em cada chamada:

# 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
)

Fecha uma ligação

Fecha sempre as ligações quando terminado para as devolver ao pool de ligações e libertar os recursos do servidor. As ligações não fechadas mantêm memória do lado do servidor e podem eventualmente esgotar o pool de ligações, fazendo com que novas tentativas de ligação bloqueem ou falhem.

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

Uma vez fechada, a ligação não pode ser utilizada:

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

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

Chamar close() várias vezes é seguro (idempotente):

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

Gestores de contexto

Use a with instrução para gerir ligações na maioria das aplicações. Garante que o controlador fecha a ligação quando o bloco termina, mesmo que ocorra uma exceção. Esta abordagem elimina o risco de ligações vazadas devido a chamadas esquecidas 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

O gestor de contexto fecha a ligação ao sair. Não confirma automaticamente nem efetua rollback das transações:

  • Sempre: Chama close() ao sair, quer tenha ocorrido ou não uma exceção.
  • close() comportamento: Se autocommit=False, quaisquer alterações não comprometidas são revertidas quando a ligação fecha.
  • Deve chamar conn.commit() explicitamente para guardar as alterações.

Esta conceção segue o comportamento da PEP 249 e evita confirmações parciais não intencionais. Se o seu código lançar uma exceção antes de chegar a commit(), a transação em curso é anulada 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 confirmação automática

Por defeito, autocommit=False, o que significa que cada instrução é executada dentro de uma transação implícita. Tem de chamar conn.commit() para guardar as alterações ou conn.rollback() para as descartar. As transações implícitas são a escolha mais segura para modificações de dados porque permitem agrupar múltiplas instruções numa única operação atómica.

Ative a confirmação automática quando pretender que cada instrução seja confirmada de imediato. O autocommit é útil para operações DDL (CREATE TABLE, ALTER INDEX), cargas de trabalho apenas de leitura ou scripts administrativos onde não é necessário agrupar transações:

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

Ative a confirmação automática para que cada instrução seja imediatamente confirmada. Utilize autocommit=True no momento da ligação, ou altere-o depois de ligar com setautocommit() ou por atribuição direta da propriedade:

# 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

Tempo limite de ligação

Defina o timeout da ligação para controlar quanto tempo o driver espera para estabelecer a ligação antes de gerar um erro. Um tempo de espera razoável de ligação é importante para aplicações implementadas em ambientes com redes pouco fiáveis ou para falhas rápidas quando um servidor é inacessível:

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

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

Um tempo limite de 0 significa que não existe tempo limite (esperar indefinidamente). Defina tempos de espera razoáveis na produção; Uma tentativa de ligação suspensa sem timeout bloqueia permanentemente o fio que chama.

Atributos de ligação

Use set_attr() para modificar o comportamento da ligação em tempo de execução. Os atributos de ligação controlam definições de driver de baixo nível, como modo de acesso, isolamento de transações e tamanho do pacote. A maioria das aplicações não precisa de alterar estes atributos, mas são úteis para cenários específicos:

  • Modo apenas de leitura: Previne escritas acidentais em consultas de relatório.
  • Isolamento de transações: Controla como as transações concorrentes interagem (uso SERIALIZABLE para consistência estrita, READ_COMMITTED para uso geral).
  • Tamanho do pacote: Ajuste para redes de alta latência ou alto débito.
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 disponíveis:

Constante Descrição
SQL_ATTR_CONNECTION_TIMEOUT Tempo limite de conexão em segundos.
SQL_ATTR_LOGIN_TIMEOUT Tempo limite de início de sessão em segundos.
SQL_ATTR_PACKET_SIZE Tamanho do pacote de rede.
SQL_ATTR_ACCESS_MODE Modo só de leitura ou de leitura e escrita.
SQL_ATTR_TXN_ISOLATION Nível de isolamento de transações.
SQL_ATTR_CURRENT_CATALOG Nome atual da base de dados.

Atributos de pré-conexão

Alguns atributos devem ser definidos antes de o driver estabelecer a ligação (por exemplo, o tempo limite de início de sessão). Passa-os 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,
    }
)

Obter informações de conexão

Use getinfo() para recuperar metadados do driver e do servidor para registo, diagnóstico ou adaptação de comportamento com base nas capacidades do 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)}")

Obtenha uma lista de constantes de informação disponíveis:

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

Personagem Search Escape

A propriedade searchescape devolve o carácter utilizado para escapar os carateres universais (% e _) nos padrões LIKE. Use-o para procurar em segurança caracteres coringa literais nas entradas do utilizador:

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

Codificação e descodificação

Configure a codificação de texto para instruções e resultados SQL. As definições padrão funcionam para a maioria das aplicações. Muda-os apenas se te ligares a um servidor que use uma codificação não UTF-8 para char/varchar colunas. A codificação que um servidor utiliza depende da intercalação da coluna:

# 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)

Codificações padrão:

Direção Tipo SQL Codificação padrão
Saída (força) SQL_WCHAR utf-16le
Inbound SQL_CHAR utf-8
Inbound SQL_WCHAR utf-16le
Inbound SQL_WMETADATA utf-16le

Melhores práticas

  • Use gestores de contexto (blocos with) para todas as ligações no código da aplicação. Garantem a limpeza mesmo quando ocorrem exceções.
  • Utilize o agrupamento de ligações para um melhor desempenho (ativado por predefinição). Consulte agrupamento de ligações.
  • Defina tempos apropriados para o seu ambiente de rede. Um timeout de 30 segundos é adequado para a maioria das implementações na cloud; aumente-a para ligações interregionais ou VPN.
  • Utilize autocommit=False (o padrão) para cenários de modificação de dados em que necessita de atomicidade transacional.
  • Utilize autocommit=True para operações DDL, consultas apenas de leitura e scripts de administração.
  • Não partilhes ligações entre tópicos. O nível de segurança das threads do controlador é 1 (as threads podem partilhar o módulo, mas não as ligações).