Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Драйвер mssql-python — это оригинальный Python-драйвер Microsoft для Microsoft SQL. Если вы предпочитаете опцию драйвера, поддерживаемого Microsoft, он предлагает:
- Нет зависимости от FreeTDS.
- Несколько одновременных курсоров для одного соединения.
- Встроенный пул соединений.
- Поддержка современного Python 3.10+.
- Нативная аутентификация Microsoft Entra.
- Объекты строк с доступом к атрибутам по умолчанию.
Основные отличия
| Функция | pymssql | mssql-python |
|---|---|---|
| Стиль параметров |
format (%s, %d) |
qmark (?) и pyformat (%(name)s) |
| Родная библиотека | FreeTDS | DDBC (в комплекте) |
| Пулинг соединений | External | Built-in |
| Курсоры на одно соединение | 1 | Multiple |
| Минимальная версия Python | 3.6 | 3.10 |
callproc() |
Поддерживается | Не реализовано |
as_dict курсор |
Extension | Объекты строк (по умолчанию) |
| Массовое копирование | conn.bulk_copy() |
cursor.bulkcopy() |
| Автоматическое подтверждение по умолчанию | Off | Off |
Основные шаги миграции
Следующие шаги пройдут по наиболее распространённым изменениям, необходимым для миграции приложения pymssql на mssql-python.
1. Обновление импорта
Замените pymssql импорт на mssql_python:
До (pymssql):
import pymssql
После (mssql-python):
import mssql_python
2. Обновление вызовов соединения
PymsSQL использует позиционные аргументы. Драйвер mssql-python использует аргументы строка подключения или ключевых слов:
До (pymssql, позиционные аргументы):
conn = pymssql.connect("<server>", "<user>", "<password>", "<database>")
До (pymssql, аргументы ключевых слов):
conn = pymssql.connect(
host=r"<server>\<instance>",
user="<login>",
password="<password>",
database="<database>"
)
После (mssql-python, строка подключения):
conn = mssql_python.connect(
"Server=<server>;"
"Database=<database>;"
"UID=<username>;"
"PWD=<password>;"
"Encrypt=yes;"
)
После (mssql-python, рекомендовано Microsoft Entra):
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
3. Обновление маркеров параметров
pymssql использует заполнители формата %s и %d. Драйвер mssql-python использует ? (qmark) или %(name)s (pyformat):
До (pymssql):
cursor.execute("SELECT * FROM Person.Person WHERE BusinessEntityID = %d AND FirstName = %s", (user_id, name))
После (mssql-python, стиль qmark):
user_id, name = 1, "Ken"
cursor.execute("SELECT * FROM Person.Person WHERE BusinessEntityID = ? AND FirstName = ?", (user_id, name))
print(cursor.fetchone())
cursor.execute(
"SELECT * FROM Person.Person WHERE BusinessEntityID = %(id)s AND FirstName = %(name)s",
{"id": user_id, "name": name}
)
print(cursor.fetchone())
4. Обновить executemany
Обновите заполнители SQL с %s/%d на ? или %(name)s:
До (pymssql):
cursor.execute("CREATE TABLE #Persons (ID INT, Name NVARCHAR(50), Department NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Persons VALUES (%d, %s, %s)",
[(1, "John", "Sales"), (2, "Jane", "Marketing")]
)
После (mssql-python, стиль qmark):
cursor.execute("IF OBJECT_ID('#Persons') IS NOT NULL DROP TABLE #Persons")
cursor.execute("CREATE TABLE #Persons (ID INT, Name NVARCHAR(50), Department NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Persons VALUES (?, ?, ?)",
[(1, "John", "Sales"), (2, "Jane", "Marketing")]
)
cursor.execute("SELECT * FROM #Persons")
for row in cursor:
print(row)
5. Используйте атрибуты Row вместо as_dict курсоров
pymssql требует as_dict=True для доступа к столбцам по имени. Драйвер mssql-python по умолчанию возвращает Row объекты, поддерживающие доступ к атрибутам и индексу:
До (pymssql):
cursor = conn.cursor(as_dict=True)
cursor.execute("SELECT BusinessEntityID, FirstName FROM Person.Person WHERE FirstName = %s", ("John",))
for row in cursor:
print("ID=%d, Name=%s" % (row["BusinessEntityID"], row["FirstName"]))
После (mssql-python, доступ к атрибутам по умолчанию):
cursor = conn.cursor()
cursor.execute("SELECT BusinessEntityID, FirstName FROM Person.Person WHERE FirstName = ?", ("John",))
for row in cursor:
print(f"ID={row.BusinessEntityID}, Name={row.FirstName}")
# Index access also works: row[0], row[1]
Миграция хранящихся процедур
Драйвер mssql-python не реализует callproc(). Используйте инструкции EXECUTE вместо этого.
Используйте EXECUTE для хранящихся процедур
PymsSQL поддерживает callproc(), а драйвер mssql-python — нет. Используйте EXECUTE вместо этого:
До (pymssql):
cursor.callproc("uspGetEmployeeManagers", (5,))
for row in cursor:
print(row)
После (mssql-python):
cursor.execute("EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = ?", (5,))
for row in cursor:
print(row)
Выходные параметры
Используйте переменные T-SQL для получения выходных значений вместо использования параметров вывода callproc():
До (pymssql):
cursor.callproc("GetProductCount", (category_id,))
count = cursor.fetchval()
После (mssql-python, переменные T-SQL):
cursor.execute("""
DECLARE @count INT;
SELECT @count = COUNT(*) FROM Production.Product
WHERE ProductSubcategoryID = ?;
SELECT @count AS ProductCount;
""", (1,))
product_count = cursor.fetchval()
print(f"Product count: {product_count}")
Миграция массовым копированием
pymssql вызывает bulk_copy() для соединения. Драйвер mssql-python вызывает bulkcopy() для курсора с большим количеством параметров:
До (pymssql):
conn.bulk_copy("##BulkDemo", [(1, 2)] * 1000)
conn.commit()
После (mssql-python):
cursor = conn.cursor()
cursor.execute("CREATE TABLE ##BulkDemo (Col1 INT, Col2 INT)")
conn.commit()
result = cursor.bulkcopy("##BulkDemo", [(1, 2)] * 1000)
print(f"Copied {result['rows_copied']} rows")
conn.commit()
cursor.execute("DROP TABLE ##BulkDemo")
conn.commit()
Метод mssql-python bulkcopy() поддерживает batch_size, timeout, column_mappings, keep_identity, check_constraints, table_lock, keep_nulls, fire_triggers и use_internal_transaction. См. Массовое копирование для получения подробной информации.
Несколько курсоров
PYMSSQL допускает только один активный курсор на каждое соединение. Драйвер mssql-python поддерживает несколько параллельных курсоров:
До (pymssql):
c1 = conn.cursor()
c1.execute("SELECT TOP 5 * FROM Person.Person")
c2 = conn.cursor()
c2.execute("SELECT TOP 5 * FROM Sales.SalesOrderHeader")
c1.fetchall()
После (mssql-python):
c1 = conn.cursor()
c1.execute("SELECT TOP 5 BusinessEntityID, FirstName FROM Person.Person")
persons = c1.fetchall()
c2 = conn.cursor()
c2.execute("SELECT TOP 5 SalesOrderID FROM Sales.SalesOrderHeader")
orders = c2.fetchall()
print(f"Persons: {len(persons)}, Orders: {len(orders)}")
Пулинг соединений
В pymsSQL нет встроенного пула. Драйвер mssql-python включает его автоматически:
Раньше (pymssql, требовался внешний пул):
from dbutils.pooled_db import PooledDB
pool = PooledDB(pymssql, host="server", user="user", password="pwd", database="db")
conn = pool.connection()
После (mssql-python, пулирование происходит автоматически):
conn = mssql_python.connect(connection_string)
conn.close()
Обработка ошибок
Драйвер mssql-python использует ту же иерархию исключений, что и pymssql, поэтому большинство обработчиков исключений требуют только изменения имени модуля:
До (pymssql):
try:
cursor.execute(query)
except pymssql.OperationalError as e:
print(f"Operation failed: {e}")
except pymssql.InterfaceError as e:
print(f"Interface error: {e}")
После (mssql-python):
try:
cursor = conn.cursor()
cursor.execute("SELECT TOP 1 * FROM Production.Product")
row = cursor.fetchone()
print(row)
except mssql_python.OperationalError as e:
print(f"Operation failed: {e}")
except mssql_python.InterfaceError as e:
print(f"Interface error: {e}")
Пример завершения миграции
Ниже показана та же функция, записанная на pymssql и перезаданная на mssql-python.
До (pymssql)
В этой версии используются позиционные аргументы connect, а также маркеры параметров as_dict=True и %d:
import pymssql
def get_orders(customer_id: int):
conn = pymssql.connect("<server>", "<user>", "<password>", "<database>")
cursor = conn.cursor(as_dict=True)
cursor.execute("""
SELECT TOP 10 SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = %d
ORDER BY OrderDate DESC
""", (customer_id,))
orders = []
for row in cursor:
orders.append({
"id": row["SalesOrderID"],
"date": row["OrderDate"],
"total": row["TotalDue"]
})
cursor.close()
conn.close()
return orders
После (mssql-python)
Ключевые структурные изменения — это маркеры параметров, стиль соединения и доступ к строкам:
import mssql_python
def get_orders(customer_id: int):
conn = mssql_python.connect(
"Server=<server>;"
"Database=<database>;"
"UID=<username>;"
"PWD=<password>;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT TOP 10 SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ?
ORDER BY OrderDate DESC
""", (customer_id,))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Структурные изменения включают:
-
import pymssql→import mssql_python. - Позиционные аргументы подключения → строка подключения с ключевыми словами.
-
%dМаркер параметров →?. -
cursor(as_dict=True)→cursor()с доступом к атрибутам (row.SalesOrderIDвместоrow["SalesOrderID"]).
Checklist
- [ ] Обновить импорт из
pymssqlвmssql_python. - [ ] Преобразовать вызовы соединений из позиционных аргументов в строки соединения.
- [ ] Преобразовать
%s/%dмаркеры параметров в?или%(name)s. - [ ] Используйте инструкции
EXECUTEдля вызовов хранимых процедур. - [ ] Используйте
Rowдоступ к атрибутам вместоas_dict=Trueкурсоров. - [ ] Мигрировать
conn.bulk_copy()вcursor.bulkcopy(). - [ ] Удалите конфигурацию внешнего пулирования соединений.
- [ ] Убрать FreeTDS из требований к развертыванию.
- [ ] Обновить имена классов для обработки исключений.
- [ ] Проверьте все запросы и хранящиеся процедуры.