Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Драйвер 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 из требований к развертыванию.
- [ ] Обновить имена классов для обработки исключений.
- [ ] Проверьте все запросы и хранящиеся процедуры.