Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Sterownik mssql-python to pierwszy oficjalny sterownik Python firmy Microsoft do Microsoft SQL. Jeśli wolisz opcję sterownika utrzymywanego przez Microsoft, oferuje:
- Brak zewnętrznej zależności sterownika ODBC.
- Wbudowane łączenie połączeń.
- Nowoczesne wsparcie dla Python 3.10+.
- Natywne uwierzytelnianie Microsoft Entra.
Podstawowe różnice
| Funkcja | pyodbc | mssql-python |
|---|---|---|
| Styl parametrów |
qmark (?) |
qmark (?) oraz pyformat (%(name)s) |
| Wymagany sterownik ODBC | Yes | No |
| Buforowanie połączeń | Zewnętrzne | Built-in |
| Minimalna wersja języka Python | 3.6 | 3.10 |
callproc() |
Wsparte | Nie zaimplementowano |
| Domyślne ustawienie automatycznego zatwierdzania | Off | Off |
Podstawowe kroki migracji
Poniższe kroki obejmują zmiany klucza niezbędne do migracji aplikacji pyodbc do mssql-python.
1. Aktualizuj importy
Zastąp import pyodbc elementem mssql_python:
Przed (pyodbc):
import pyodbc
Po (mssql-python):
import mssql_python
2. Aktualizacja ciągów połączeń
Usuń DRIVER= słowo kluczowe i zaktualizuj metodę uwierzytelniania:
Wcześniej (pyodbc, wymaga sterownika ODBC):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
Po (mssql-python, bez potrzeby sterownika, przy użyciu uwierzytelniania Microsoft Entra):
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
3. Pozostaw swoje zapytania bez zmian
Sterownik mssql-python obsługuje oba style parametrów: ? (qmark) i %(name)s (pyformat). Twoje istniejące ? zapytania działają bez zmian:
Przed (pyodbc):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
Po (mssql-python, to samo zapytanie):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
4. Pozostaw executemany bez zmian
Dotychczasowe wywołania executemany z krotkami i znacznikami ? działają bez zmian:
Przed (pyodbc):
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)
Po (mssql-python, ten sam kod):
cursor.execute("DROP TABLE IF EXISTS #MigrateDemo")
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)
Migracja procedur przechowywanych
Sterownik mssql-python nie implementuje callproc(). W poniższych sekcjach pokazano, jak zamiast tego używać EXECUTE.
Użyj EXECUTE dla procedur przechowywanych
Sterownik pyodbc obsługuje callproc(), ale sterownik mssql-python nie. Użyj EXECUTE zamiast tego:
Przed (pyodbc):
cursor.callproc("dbo.uspGetEmployeeManagers", (5,))
results = cursor.fetchall()
Po (mssql-python):
cursor.execute(
"EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s",
{"id": 5}
)
results = cursor.fetchall()
print(f"Got {len(results)} rows")
Parametry wyjściowe
Używaj zmiennych T-SQL do rejestrowania wartości wyjściowych zamiast polegać na parametrach callproc() wyjściowych:
Przed (pyodbc, używając callproc):
params = (category_id, pyodbc.SQL_INTEGER)
cursor.callproc("dbo.GetProductCount", params)
count = params[1].value
Po (mssql-python, używając zmiennych T-SQL):
cursor.execute(
"""
DECLARE @count INT;
SELECT @count = COUNT(*) FROM Production.Product
WHERE ProductSubcategoryID = %(cat_id)s;
SELECT @count AS ProductCount;
""",
{"cat_id": 1}
)
product_count = cursor.fetchval()
print(f"Product count: {product_count}")
Migracje specyficzne dla funkcji
Poniższe sekcje obejmują konkretne funkcje pyodbc oraz ich odpowiedniki mssql-python.
Łańcuchy połączenia
| słowo kluczowe pyodbc | Słowo kluczowe mssql-python | Notatki |
|---|---|---|
DRIVER={...} |
Nie jest wymagany | Sterownik ODBC jest dołączony wewnętrznie. |
SERVER= |
Server= |
Brak zmian zachowania. |
DATABASE= |
Database= |
Brak zmian zachowania. |
Trusted_Connection= |
Trusted_Connection= |
Brak zmian zachowania. |
UID= / PWD= |
UID= / PWD= |
Brak zmian zachowania. |
Authentication= |
Authentication= |
Akceptuje te same wartości. |
Autozatwierdzanie
Zachowanie automatycznego zatwierdzania jest identyczne w obu sterownikach:
pyodbc:
conn.autocommit = True
pyodbc.connect(connection_string, autocommit=True)
mssql-python:
conn.autocommit = True
Wkładki zbiorcze
Aby przyspieszyć duże INSERT partie, użytkownicy pyodbc ustawiają fast_executemany = True. Sterownik mssql-python już optymalizuje executemany dla partii wsadowych z parametrami, więc umiarkowana liczba operacji wstawiania nie wymaga żadnej specjalnej flagi. Dla dużych ładowań danych preferujemy bulkcopy(), które przesyła wiersze przez protokół kopiowania masowego i jest znacznie szybsze niż wydawanie pojedynczych INSERT instrukcji. Pełny przepływ pracy znajdziesz w artykule Użyj kopii masowej.
pyodbc:
cursor.fast_executemany = True
cursor.executemany(query, data)
Po (mssql-python) umiarkuj partie z :executemany
cursor.execute("DROP TABLE IF EXISTS #BulkTarget")
cursor.execute("CREATE TABLE #BulkTarget (ID INT, Name NVARCHAR(50))")
data = [(i, f"Item {i}") for i in range(100)]
cursor.executemany("INSERT INTO #BulkTarget (ID, Name) VALUES (?, ?)", data)
conn.commit()
Po „mssql-python”, duże obciążenia z bulkcopy (zalecane):
cursor.execute("IF OBJECT_ID('##BulkTarget') IS NOT NULL DROP TABLE ##BulkTarget")
cursor.execute("CREATE TABLE ##BulkTarget (ID INT, Name NVARCHAR(50))")
conn.commit() # Commit DDL before bulkcopy
data = [(i, f"Item {i}") for i in range(100)]
result = cursor.bulkcopy("##BulkTarget", data)
print(f"Bulk copied {result['rows_copied']} rows")
cursor.execute("DROP TABLE ##BulkTarget")
conn.commit()
Generator wierszy
Sterownik mssql-python zwraca obiekty Row, które domyślnie umożliwiają dostęp do atrybutów, bez konieczności użycia niestandardowej fabryki wierszy:
Pyodbc (Custom Row Factory):
def namedtuple_row_factory(cursor):
from collections import namedtuple
columns = [col[0] for col in cursor.description]
Row = namedtuple("Row", columns)
return Row
mssql-python (domyślny dostęp do atrybutów):
cursor.execute("SELECT Name, ListPrice FROM Production.Product")
row = cursor.fetchone()
print(row.Name) # Attribute access works directly
print(row[0]) # Index access also works
Obsługa błędów
Sterownik mssql-python używa tej samej hierarchii wyjątków co pyodbc, więc większość obsługiwaczy wyjątków wymaga jedynie zmiany nazwy modułu.
Hierarchia wyjątków
Nazwy klas wyjątków odwzorowują się bezpośrednio między sterownikami:
pyodbc:
try:
cursor.execute(query)
except pyodbc.Error as e:
pass
except pyodbc.DatabaseError as e:
pass
except pyodbc.OperationalError as e:
pass
mssql-python:
try:
cursor.execute("SELECT TOP 1 * FROM Production.Product")
print(cursor.fetchone())
except mssql_python.Error as e:
pass
except mssql_python.DatabaseError as e:
pass
except mssql_python.OperationalError as e:
pass
Szczegóły błędu
Oba sterowniki ujawniają szczegóły błędów za pomocą argumentów wyjątków:
pyodbc:
try:
cursor.execute(query)
except pyodbc.Error as e:
sqlstate = e.args[0]
message = e.args[1]
mssql-python:
try:
cursor.execute("SELECT TOP 1 * FROM NonExistentTable_XYZ")
except mssql_python.Error as e:
# Error message contains SQLSTATE and details
print(str(e))
Buforowanie połączeń
Sterownik mssql-python domyślnie zawiera pulowanie połączeń, więc zewnętrzne biblioteki pulujące nie są już potrzebne.
Usuń zewnętrzne buforowanie
Jeśli używałeś zewnętrznej puli z pyodbc, sterownik mssql-python ma to wbudowane:
Przed (pyodbc external pool):
from dbutils.pooled_db import PooledDB
pool = PooledDB(pyodbc, 5, driver="{ODBC Driver 18 for SQL Server}",
server="your_server", database="your_database",
uid="your_username", pwd="your_password")
conn = pool.connection()
Po (wbudowane buforowanie połączeń mssql-python):
conn = mssql_python.connect(connection_string)
conn.close()
Konfiguruj pulę
Nadpisz domyślny rozmiar puli i limit czasu za pomocą mssql_python.pooling():
import mssql_python
mssql_python.pooling()
Kompletny przykład migracji
Poniżej przedstawiono tę samą funkcję napisaną w pyodbc, a następnie przepisaną w mssql-python.
Przed (pyodbc)
Ta wersja używa parametrów połączenia pyodbc ze słowem kluczowym DRIVER:
import pyodbc
from datetime import date
def get_orders(customer_id: int, start_date: date):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ? AND OrderDate >= ?
ORDER BY OrderDate DESC
""", (customer_id, start_date))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Po (mssql-python)
Ta wersja usuwa to DRIVER słowo kluczowe. Wszystkie zapytania, parametry i wzorce dostępu do wierszy pozostają identyczne:
import mssql_python
from datetime import date
def get_orders(customer_id: int, start_date: date):
conn = mssql_python.connect(
"Server=localhost;"
"Database=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ? AND OrderDate >= ?
ORDER BY OrderDate DESC
""", (customer_id, start_date))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Jedynymi zmianami są instrukcja importu i parametry połączenia (słowo kluczowe DRIVER nie jest potrzebne). Każde zapytanie, parametr, wzór pobierania i dostęp do wiersza pozostają identyczne.
Testowanie migracji
Przed zakończeniem migracji uruchom te same zapytania na obu sterownikach i porównaj wyniki, aby potwierdzić równoważne zachowanie.
Zweryfikować równoważne zachowanie
Użyj funkcji porównawczej, która wykonuje to samo zapytanie na obu sterownikach i potwierdza, że wyniki się zgadzają:
import pyodbc
import mssql_python
def compare_results(pyodbc_conn_str: str, mssql_conn_str: str, query: str):
"""Compare results from both drivers."""
# pyodbc query
pyodbc_conn = pyodbc.connect(pyodbc_conn_str)
pyodbc_cursor = pyodbc_conn.cursor()
pyodbc_cursor.execute(query)
pyodbc_results = pyodbc_cursor.fetchall()
pyodbc_conn.close()
# mssql-python query
mssql_conn = mssql_python.connect(mssql_conn_str)
mssql_cursor = mssql_conn.cursor()
mssql_cursor.execute(query)
mssql_results = mssql_cursor.fetchall()
mssql_conn.close()
# Compare
assert len(pyodbc_results) == len(mssql_results)
for p_row, m_row in zip(pyodbc_results, mssql_results):
assert tuple(p_row) == tuple(m_row)
print(f"Results match: {len(pyodbc_results)} rows")
Lista kontrolna
- [ ] Aktualizuj importy z
pyodbcdo .mssql_python - [ ] Usuń
DRIVER=ze znaków połączeń. - [ ] Zachowuj istniejące
?zapytania parametrów (działają as-is). - [ ] Używaj
EXECUTEinstrukcji do wywołań procedur przechowywanych. - [ ] Usuń konfigurację pulowania połączeń zewnętrznych.
- [ ] Aktualizuj nazwy klas obsługujących wyjątki.
- [ ] Testuj wszystkie zapytania i procedury przechowywane.
- [ ] Weryfikacja obsługi typów danych (szczególnie dziesiętnych i dat).
- [ ] Usuń sterownik ODBC z wymagań wdrożenia.