python pymssql — pymssql模組使用指南
前言
最近在學習python,發現好像沒有對pymssql的詳細說明,於是乎把官方文件學習一遍,重要部分做個歸檔,方便自己以後查閱。
pymssql是python用來連線Microsoft SQL Server的一個工具庫(package)。其包含兩個模組:
- pymssql:遵從DB-API1規範的介面
- _mssql:效能更佳、更易於使用
從版本2.1.x起,整個庫的實現基於FreeTDS2的db-lib元件。
pymssql的架構如下:
在Windows下的安裝很簡單,下載安裝個相對新版的python,具體來說:
- Python 2.x: 2.7以上
- Python 3.x: 3.3以上
然後開啟命令列:
pip install pymssql
然後就自動安裝上了,好像FreeTDS之後的支援庫都會自動幫忙安好。
另外注意為了後面的使用,需要自己安裝好Microsoft SQL Server,2005以上的版本。
pymssql模組使用
以下示例程式基於官方的示例,並進行了一定的修改,主要是刪改了些程式碼以及添加了很多註釋。
基本使用流程
pymssql的使用十分簡單,基本就如下幾個步驟
- 建立連結:使用connect()建立連線並獲取Connection物件
- 互動操作:獲取Connection物件的Cursor物件,然後使用Cursor物件的各種方法與資料庫進行互動
- 關閉連結
本章假設你已經配置好環境並且在本地資料庫中有一個叫tempdb的資料庫,有一個使用者的使用者名稱為sa,密碼為123456。
以下程式簡單示例了上述步驟並建立好了測試用資料庫。
import pymssql
#sql伺服器名,這裡(127.0.0.1)是本地資料庫IP
serverName = '127.0.0.1'
#登陸使用者名稱和密碼
userName = 'sa'
passWord = '123456'
#建立連線並獲取cursor
conn = pymssql.connect(serverName , userName , passWord, "tempdb")
cursor = conn. cursor()
# 建立測試表 persons,包含欄位:ID、name、salesrep
cursor.execute("""
IF OBJECT_ID('persons', 'U') IS NOT NULL
DROP TABLE persons
CREATE TABLE persons (
id INT NOT NULL,
name VARCHAR(100),
salesrep VARCHAR(100),
PRIMARY KEY(id)
)
""")
# 插入三條測試資料
cursor.executemany(
"INSERT INTO persons VALUES (%d, %s, %s)",
[(1, 'John Smith', 'John Doe'),
(2, 'Jane Doe', 'Joe Dog'),
(3, 'Mike T.', 'Sarah H.')])
# 如果連線時沒有設定autocommit為True的話,必須主動呼叫commit() 來儲存更改。
conn.commit()
# 查詢記錄
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
# 獲取一條記錄
row = cursor.fetchone()
# 迴圈列印記錄(這裡只有一條,所以只打印出一條)
while row:
print("ID=%d, Name=%s" % (row[0], row[1]))
row = cursor.fetchone()
# 連線用完後記得關閉以釋放資源
conn.close()
後面較為詳細的分開講解下各個步驟
建立連線
因為這篇文章講的是pymssql模組(如上所述還有一個_mssql模組)所以要import pymssql。
為了建立連線,需要呼叫pymssql.connect()方法,這個方法會返回一個Connection物件。
使用者驗證登陸
可能比較常用的就是如上面程式中所用的使用者名稱+密碼的登陸方式了:
conn = pymssql.connect(serverName , userName , passWord, "tempdb")
等價於:
conn = pymssql.connect(server = serverName , user = userName , password = passWord, database = "tempdb")
第二種用關鍵字的方式可以按任意順序傳遞各引數(好吧,這其實是python的基礎知識)。
Windows身份認證登陸
登陸自己電腦上的資料庫時,Windows身份認證的方式登陸是個很好用的方法。因為不需要賬號密碼:
conn = pymssql.connect(server = serverName , database = "tempdb")
簡單來說,只要不填賬號密碼,就會自動用Windows身份認證的方式來登陸了。
其他幾個常用選項
- database(str):指定的是預設資料庫,如果不需要的話,上述例子中其實可以不寫。但是這樣的話,那你的SQL語句中就得在最前面加上"USE tempdb ……"了,sql server用的多的應該知道怎麼回事。
- as_dict(bool) :如果設定為True,則後面的查詢結果返回的是字典,關鍵字為查詢結果的列名;否則(預設)返回的為list。
- autocommit(bool):預設為False,這樣如果對資料表進行更改,則需要手動呼叫commit來提交操作。
- port(str):指定伺服器的TCP埠,如果你沒有改過的話使用預設的就好。
其他選項詳見文件。
互動操作
在連線建立成功後,與資料庫的互動主要是通過Cursor物件進行的:
cursor = conn.cursor()
提交sql命令
如上示例,sql指令通過execute系列方法來執行:
cursor.execute('sql語句')
呼叫儲存過程
如果要呼叫儲存過程,則使用Cursor物件的callproc方法
# 建立一個儲存過程
cursor.execute("""
CREATE PROCEDURE FindPerson
@name VARCHAR(100)
AS BEGIN
SELECT * FROM persons WHERE name = @name
END
""")
# 呼叫上面的儲存過程
cursor.callproc('FindPerson', ('Jane Doe',))
提交修改
如果對資料進行了修改,且在連線時沒有把autocommit設定為True,則需要手動呼叫commit進行提交修改。
conn.commit()
獲取結果
如果執行的是有返回值的sql語句,則可以通過Cursor物件的fetch系列方法來獲取結果,結果預設為元組型別:
# 查詢persons表中記錄數
cursor.execute("SELECT COUNT(*) FROM persons")
# 結果為3
cnt = cursor.fetchone()[0]
如果返回多條記錄,可以像這樣遍歷所有結果:
cursor.execute('SELECT * FROM persons')
# 遍歷輸出persons表中所有資料
row = cursor.fetchone()
while row:
print("ID=%d, Name=%s" % (row[0], row[1]))
row = cursor.fetchone()
或者:
# 這裡寫sql語句的和上例不完全一樣只是為了示例execute的其他用法
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:
print('row = %r' % (row,))
如果指定了as_dict為True,則返回結果變為字典型別,這樣就能通過列名來訪問結果了:
# 除了在建立連線時指定,還可以在這裡指定as_dict=True
cursor = conn.cursor(as_dict=True)
cursor.execute('SELECT * FROM persons')
for row in cursor:
print("ID=%d, Name=%s" % (row['id'], row['name']))
另外,還可以使用fetchmany和fetchall來一次性獲取指定數量或者所有的結果。
Cursor物件注意事項
一條連結在任何時候只會有一個Cursor物件處於查詢狀態,這是因為底層的TDS協議沒有客戶端側的Cursor,協議要求客戶端在進行下一次查詢前先完成上一次的。因此如果你想同時在一個連線上進行兩個查詢的話可能會出現各種驚喜,也許在使用多執行緒等方式的時候需要特別注意這點:
c1 = conn.cursor()
c1.execute('SELECT * FROM persons')
c2 = conn.cursor()
c2.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
print( "all persons" )
print( c1.fetchall() ) # 展示的是 c2 的結果!
print( "John Doe" )
print( c2.fetchall() ) # 沒有任何結果,因為已經被上一條輸出了
有兩種解決方案:
- 另外建一條連結,每條連結都能有一個進行中的查詢,因此這樣就可以有多個查詢同步進行了。
- 進行下一次查詢前先使用fetchall獲取上一次的所有結果:
c1.execute('SELECT ...')
c1_list = c1.fetchall()
c2.execute('SELECT ...')
c2_list = c2.fetchall()
關閉連結
操作完成後應該呼叫close方法來關閉連結並釋放資源:
conn.close()
可以使用with語句來處理Connection和cursor物件,這樣就不需要手動關閉他們了:
with pymssql.connect(server, user, password, "tempdb") as conn:
with conn.cursor(as_dict=True) as cursor:
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:
print("ID=%d, Name=%s" % (row['id'], row['name']))