Управление соединениями с помощью mssql-python

Большинство приложений следуют простой схеме: открывают соединение, запускают запросы, закрывают соединение. Следующие разделы охватывают открытие и закрытие соединений, использование контекстных менеджеров, настройку автокоммита и работу с атрибутами соединения.

Откройте соединение

Используйте функцию connect() для установки соединения. Передайте строку подключения с данными вашего сервера, базы данных и данными для аутентификации:

import mssql_python

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

Функция connect() принимает:

  • Строка подключения в качестве первого позиционного аргумента или ключевое слово connection_str.
  • Отдельные ключевые слова, которые драйвер объединяет в строку подключения.
  • Другие варианты, такие как autocommit, timeoutи attrs_before.

Можно смешивать оба подхода. Ключевые слова переопределяют значения в строке подключения, что полезно, когда вы храните базовую строку подключения в конфигурации и переопределяете такие параметры, как timeout, при каждом вызове:

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

Закройте соединение

Всегда закрывайте соединения после завершения работы, чтобы вернуть их в пул соединений и освободить ресурсы сервера. Незакрытые соединения содержат серверную память и могут в конечном итоге исчерпать пул соединений, вызывая блокировку или неудачу новых попыток подключения.

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

После закрытия соединение нельзя использовать:

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

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

Вызывать close() несколько раз безопасно (идемпотентно):

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

Менеджеры контекста

Используйте оператор with для управления соединениями в большинстве приложений. Это гарантирует, что драйвер закроет соединение при выходе из блока, даже если произойдёт исключение. Этот подход устраняет риск утечки соединений из-за забытых 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

Менеджер контекста закрывает соединение при выходе. Он не фиксирует и не откатывает транзакции автоматически:

  • Всегда: вызывает close() при выходе независимо от того, возникло исключение или нет.
  • close() Поведение: Если autocommit=False, любые незафиксированные изменения откатываются при закрытии соединения.
  • Чтобы сохранить изменения, необходимо явно вызвать conn.commit()

Это решение соответствует поведению, определённому в PEP 249, и предотвращает случайные частичные коммиты. Если ваш код вызывает исключение до достижения commit(), текущая транзакция безопасно откатывается назад:

# 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

Режим автоматической фиксации транзакций

По умолчанию autocommit=False, что означает, что каждая инструкция выполняется внутри неявной транзакции. Вы должны вызвать conn.commit(), чтобы сохранить изменения, или conn.rollback(), чтобы отменить их. Неявные транзакции — самый безопасный выбор для модификации данных, так как позволяют сгруппировать несколько операторов в одну атомарную операцию.

Включите автоматическую фиксацию, если хотите, чтобы каждая инструкция фиксировалась сразу. Автоматическая фиксация полезна для операций DDL (CREATE TABLE, ALTER INDEX), нагрузок только на чтение или административных скриптов, где группировка транзакций не нужна:

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

Включите автокоммит для каждой инструкции, чтобы изменения подтверждались немедленно. Используйте autocommit=True при подключении или переключите его после подключения с помощью setautocommit() или прямого присваивания свойства:

# 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

Время соединения истекло

Установите тайм-аут соединения, чтобы контролировать, сколько времени драйвер ждёт установления соединения, прежде чем появляется ошибка. Разумный тайм-аут соединения важен для приложений, развернутых в средах с ненадёжными сетями или для быстрых сбоев, когда сервер недоступен:

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

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

Тайм-аут 0 означает отсутствие тайм-аута (ждать бесконечно). Определите разумные тайм-ауты в производстве; Попытка зависающего соединения без тайм-аута навсегда блокирует поток вызова.

Атрибуты подключения

Используйте set_attr() для изменения поведения соединения во время выполнения. Атрибуты соединения управляют низкоуровневыми настройками драйверов, такими как режим доступа, изоляция транзакций и размер пакета. Большинству приложений не нужно менять эти характеристики, но они полезны в конкретных ситуациях:

  • Режим только для чтения: предотвращает случайные записи в запросах по отчётам.
  • Изоляция транзакций: Контролирует, как параллельные транзакции взаимодействуют (используется SERIALIZABLE для строгой согласованности, READ_COMMITTED для общего использования).
  • Размер пакета: настройте для сетей с высокой задержкой или высокой пропускной способностью.
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)

Доступные атрибуты:

Постоянный Описание
SQL_ATTR_CONNECTION_TIMEOUT Время ожидания подключения в секундах.
SQL_ATTR_LOGIN_TIMEOUT Тайм-аут входа через секунды.
SQL_ATTR_PACKET_SIZE Размер сетевого пакета.
SQL_ATTR_ACCESS_MODE Режим только чтения или чтение-запись.
SQL_ATTR_TXN_ISOLATION Уровень изоляции транзакций.
SQL_ATTR_CURRENT_CATALOG Текущее название базы данных.

Атрибуты предсоединения

Некоторые атрибуты должны быть установлены до того, как водитель установит соединение (например, тайм-аут входа). Пропустите их через attrs_before:

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

Получение сведений о подключении

Используйте getinfo() для получения метаданных драйверов и серверов для логирования, диагностики или адаптации поведения в зависимости от возможностей сервера:

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)}")

Получите список доступных информационных констант:

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

Символ экранирования поиска

Свойство searchescape возвращает символ, используемый для экранирования подстановочных знаков (% и _) в шаблонах LIKE. Используйте его для безопасного поиска буквальных символов подстановки в пользовательском вводе:

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

Кодировка и декодирование

Настройте кодировку текста для SQL-запросов и результатов. Настройки по умолчанию работают для большинства приложений. Меняйте их только если подключаетесь к серверу, который использует не-UTF-8 кодировку для char/varchar столбцов. Кодировка, используемая сервером, зависит от сортировки столбцов:

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

Кодировки по умолчанию:

Направление Тип SQL Кодирование по умолчанию
Исходящий (str) SQL_WCHAR utf-16le
Inbound SQL_CHAR utf-8
Inbound SQL_WCHAR utf-16le
Inbound SQL_WMETADATA utf-16le

Лучшие практики

  • Используйте контекстные менеджеры (with блоки) для всех соединений в коде приложения. Они гарантируют уборку даже при возникновении исключений.
  • Используйте пул соединений для лучшей производительности (по умолчанию включён). См. Пулирование соединений.
  • Установите соответствующие тайм-ауты для вашей сетевой среды. 30-секундный тайм-аут подходит большинству облачных развертываний; Увеличьте его для межрегиональных или VPN-соединений.
  • Использование autocommit=False (по умолчанию) для сценариев модификации данных, где нужна транзакционная атомичность.
  • Использование autocommit=True для операций DDL, запросов только для чтения и скриптов администратора.
  • Не делитесь связями между темами. Уровень потокобезопасности драйвера равен 1 (потоки могут совместно использовать модуль, но не подключения).