Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Driver mssql-python adalah driver Python pihak pertama Microsoft untuk Microsoft SQL. Jika Anda lebih suka opsi driver yang dikelola Microsoft, ia menawarkan:
- Tidak ada dependensi FreeTDS.
- Beberapa kursor simultan per koneksi.
- Pool koneksi bawaan.
- Dukungan modern untuk Python 3.10+
- Autentikasi Microsoft Entra asli.
- Objek baris dengan akses atribut secara default.
Perbedaan utama
| Feature | Pymssql | mssql-python |
|---|---|---|
| Gaya parameter |
format (%s, %d) |
qmark (?) dan pyformat (%(name)s) |
| Perpustakaan asli | FreeTDS | DDBC (disertakan dalam paket) |
| Pemanfaatan koneksi | Eksternal | Built-in |
| Kursor per koneksi | 1 | Multiple |
| Python minimum | 3.6 | 3.10 |
callproc() |
Dukungan | Tidak diimplementasikan |
as_dict kursor |
Extension | Objek baris (bawaan) |
| Penyalinan massal | conn.bulk_copy() |
cursor.bulkcopy() |
| Autocommit bawaan | Off | Off |
Langkah-langkah migrasi dasar
Langkah-langkah berikut membahas perubahan paling umum yang diperlukan untuk memigrasikan aplikasi pymssql ke mssql-python.
1. Perbarui impor
Ganti pymssql impor dengan mssql_python:
Sebelum (pymssql):
import pymssql
Setelah (mssql-python):
import mssql_python
2. Perbarui panggilan koneksi
pymssql menggunakan argumen posisi. Driver mssql-python menggunakan string koneksi atau argumen kata kunci:
Sebelum (pymssql, argumen posisi):
conn = pymssql.connect("<server>", "<user>", "<password>", "<database>")
Sebelum (pymssql, argumen kata kunci):
conn = pymssql.connect(
host=r"<server>\<instance>",
user="<login>",
password="<password>",
database="<database>"
)
Setelah (mssql-python, string koneksi):
conn = mssql_python.connect(
"Server=<server>;"
"Database=<database>;"
"UID=<username>;"
"PWD=<password>;"
"Encrypt=yes;"
)
Setelah (mssql-python, Microsoft Entra direkomendasikan):
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
3. Perbarui penanda parameter
pymssql menggunakan %s dan %d memformat placeholder. Driver mssql-python menggunakan ? (qmark) atau %(name)s (pyformat):
Sebelum (pymssql):
cursor.execute("SELECT * FROM Person.Person WHERE BusinessEntityID = %d AND FirstName = %s", (user_id, name))
Setelah (mssql-python, gaya 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. Perbarui executemany
Perbarui placeholder SQL dari %s/%d ke ? atau %(name)s:
Sebelum (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")]
)
Setelah (mssql-python, gaya 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. Gunakan atribut Row, bukan kursor as_dict
PymsSQL memerlukan as_dict=True akses kolom berdasarkan nama. Driver mssql-python mengembalikan Row objek yang mendukung akses atribut dan indeks secara default:
Sebelum (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"]))
Setelah (mssql-python, akses atribut secara default):
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]
Migrasi prosedur tersimpan
Driver mssql-python tidak mengimplementasikan callproc(). Gunakan EXECUTE pernyataan sebagai gantinya.
Gunakan EXECUTE untuk prosedur tersimpan
Pymssql mendukung callproc(), tetapi driver mssql-python tidak. Gunakan EXECUTE sebagai gantinya:
Sebelum (pymssql):
cursor.callproc("uspGetEmployeeManagers", (5,))
for row in cursor:
print(row)
Setelah (mssql-python):
cursor.execute("EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = ?", (5,))
for row in cursor:
print(row)
Parameter output
Gunakan variabel T-SQL untuk menangkap nilai output alih-alih mengandalkan callproc() parameter output:
Sebelum (pymssql):
cursor.callproc("GetProductCount", (category_id,))
count = cursor.fetchval()
Setelah (mssql-python, variabel 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}")
Migrasi salinan massal
pymssql memanggil bulk_copy() pada koneksi. Driver mssql-python memanggil bulkcopy() pada kursor dengan lebih banyak opsi:
Sebelum (pymssql):
conn.bulk_copy("##BulkDemo", [(1, 2)] * 1000)
conn.commit()
Setelah (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()
Metode mssql-python bulkcopy() mendukung batch_size, timeout, column_mappings, keep_identitycheck_constraintstable_lockkeep_nullsfire_triggersdan .use_internal_transaction Lihat Salinan massal untuk detailnya.
Beberapa kursor
PymsSQL hanya mengizinkan satu kursor aktif per koneksi. Driver mssql-python mendukung beberapa kursor bersamaan:
Sebelum (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()
Setelah (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)}")
Pemanfaatan koneksi
PymsSQL tidak memiliki pengumpulan bawaan. Driver mssql-python menyertakannya secara otomatis:
Sebelum (pymssql, memerlukan pool eksternal):
from dbutils.pooled_db import PooledDB
pool = PooledDB(pymssql, host="server", user="user", password="pwd", database="db")
conn = pool.connection()
Setelah (mssql-python, pengumpulan otomatis):
conn = mssql_python.connect(connection_string)
conn.close()
Penanganan kesalahan
Driver mssql-python menggunakan hierarki pengecualian yang sama dengan pymssql, sehingga sebagian besar penanganan pengecualian hanya memerlukan perubahan nama modul:
Sebelum (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}")
Setelah (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}")
Contoh migrasi lengkap
Berikut ini menunjukkan fungsi yang sama yang ditulis dengan pymssql dan kemudian ditulis ulang dengan mssql-python.
Sebelumnya (pymssql)
Versi ini menggunakan argumen koneksi posisional, as_dict=True, dan %d penanda parameter:
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
Setelah (mssql-python)
Perubahan struktural utama adalah penanda parameter, gaya koneksi, dan akses baris:
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
Perubahan struktural adalah:
-
import pymssql→import mssql_python. - Argumen koneksi posisional → string koneksi dengan kata kunci.
-
%dpenanda parameter →?. -
cursor(as_dict=True)→cursor()dengan akses atribut (row.SalesOrderIDbukanrow["SalesOrderID"]).
Checklist
- [ ] Perbarui impor dari
pymssqlkemssql_python. - [ ] Konversi panggilan koneksi dari argumen posisi ke string koneksi.
- [ ] Konversi
%s/%dpenanda parameter menjadi?atau .%(name)s - [ ] Gunakan pernyataan
EXECUTEuntuk pemanggilan prosedur tersimpan. - [ ] Gunakan akses atribut
Rowalih-alih kursoras_dict=True. - [ ] Bermigrasi
conn.bulk_copy()kecursor.bulkcopy(). - [ ] Hapus konfigurasi pengumpulan koneksi eksternal.
- [ ] Hapus FreeTDS dari persyaratan penyebaran.
- [ ] Perbarui nama kelas penanganan pengecualian.
- [ ] Uji semua kueri dan prosedur tersimpan.