MySQLdb
MySQLdb是一款較為底層的,python連接mysql用的模塊。和更加高級的,提供ORM的模塊不同,MySQLdb主要還是聚焦於如何和數據庫進行連接和進行基本的操作,操作的體現形式主要還是進行SQL語句的執行。
■ 安裝
在Linux下
pip install MySQL-python
如果安裝之后仍不能正常運行,嘗試用yum install MySQL-python,因為這個模塊需要一些第三方程序來運行的。
如果是在windows環境下安裝的話那么可以直接下載一個安裝程序來安裝已經編譯好的模塊。比如去【http://www.codegood.com/downloads】下載。
■ 基本使用
MySQLdb提供了connect方法來建立一個與數據庫的連接,調用這個對象的close方法來關閉一個連接。通過這個連接可以創建出一個游標對象,通過游標對象來進行數據的增刪查改。
import MySQLdb db = MySQLdb.connect(host='localhost',user='weiyz',passwd='123456',db='test_DB',charset='utf-8') cursor = db.cursor() #創建一個游標對象 cursor.excute("use test_table;show tables;") #執行SQL語句,注意這里不返回結果,只是執行而已 res = cursor.fetchall() #fetchall方法返回所有匹配的元組,給出一個大元組(每個元素還是一個元組) ####或者也可以這樣#### res = cursor.fetchone() while res: print res res = cursor.fetchone() #fetchone只給出一條數據,然后游標后移。游標移動過最后一行數據后再fetch就得到None
db.close()
另外關於db這個連接對象,除了可以實例化一個游標對象之外,還可以進行commit(),rollback()等操作。
■ 游標對象的執行和返回數據
就像上面例子中提到的那樣,cursor可以調用execute來執行一定的SQL語句,也可以fetchone或者fetchall來得到返回的數據。接下來詳細看一下cursor的各個方法:
callproc(procname[,args]) 調用一個叫做procname的存儲過程
close() 游標也有關閉方法,游標被關閉之后就不能再移動,更不能被fetch
execute(query[,args]) query是一個SQL串,args是一個序列或者映射,將依次為query中的變量賦值。關於query串中的變量設置下面會細講。這個方法返回的值是影響的行數(比如查詢SQL就返回查詢到了多少行,增刪SQL就返回增刪了多少行)
executemany(query[,args]) 這個方法和execute是類似的,只不過它是重復好幾次執行execute,args也是一個“相同長度序列的序列”,每一次執行都把一個序列中的項對應到query的變量中去。據說executemany在效率上比execute高出很多, 在批量插入、批量更新時可以考慮使用。需要注意的是,這個方法是一個整體,如果想要進行多次查詢操作用這個方法的話往往只能得到最后一個參數約束到SQL中得到的結果集。
fetchone/fetchall() 獲得一行/所有行結果
fetchmany([size]) size指出了我到底要獲取多少行的數據,如果能夠返回的行數小於要求的行數的話,就以少的為准。
nextset() 放棄所有結果集中結果直接跳到下個結果集(如果有的話)。如果沒有更多結果集就返回None,否則返回True,接下來的fetch操作將會從新結果集返回數據了。所謂結果集,就是比如連着執行兩條SQL語句的話,如果不調用nextset,那么fetch來fetch去總是只能得到第一個語句的結果內容,調用了這個之后就可以看到下一個語句執行結果的內容了。
rowcount 這個屬性代表了上一次execute*方法得到結果的結果行數,如果是-1則代表了上一次返回結果沒有結果集且行數無法確定。
● query字符串中的變量設置
query中可以設置變量來動態地生成一些SQL語句,從而使得操作更加靈活多變。query中的變量大多數時候用在查詢操作里面,因為沒有統一的格式規定,設定變量的方法有很多種形式。比如可以用?,格式化字符串,數字等等。下面統一用格式化字符串的形式來表示。
比如"select Sno,Sname from Student where Sno=%s"
“select * from Client where level > %d and gid = %s"
這些變量可以和execute*方法的args參數進行配合以具體化。對於execute方法而言,因為只執行一次SQL,所有它的args只需要一個元組(序列),元組各元素和SQL串中的變量一一對應。而對於executemany方法,args是一系列上面那樣的元組組成的一個元組(序列),相當於以一個循環依次把大元組中的各個小元組約束進SQL執行。實例:
SQL = """ select * from Client where level > %d and gid = %s """ cursor.execute(SQL,(2,'10001')) #需要注意的是,如果只有一個變量,args不要寫類似('10001')這樣,因為這判是<type 'str'>而不是tuple,應該寫('10001',) print cursor.fetchone() ##如果同樣的SQL,用executemany來查詢多個結果集的話 cursor.executemany(SQL,(\ (2,'10001'),\ (2,'10002'),\ (1,'10003'),\ )\ ) #如此就相當於依次把2,10001;2,10002和1,10003約束給SQL在執行,但是從查詢數據的角度來看,只能得到10003的數據,
#因為executemany是一口氣執行完的,fetch只能fetch到最后一個數字。所以executemany比較適合用於寫而不是讀操作。
■ 事務操作
因為MySQLdb是比較底層的模塊,對數據庫的操作都基於最基本的SQL語句,所以也就無所謂細講如何增刪查改了(反正到頭來都是調用SQL),不過對於事務,還是有必要提及。
事務是通過接口對於數據庫做出操作的最基本操作單位,可以看成是一系列操作的集合。一個事務具有以下特性:
原子性,事務中的所有操作要么都做要么都不做。
一致性,事務可以把數據庫從一個一致性狀態轉變成另一個一致性狀態
永久性,事務對數據庫做出的改變是永久的。
隔離性,事務不應該被其他並行運行的事務所影響,事務間彼此應該是獨立的
基於以上對於事務的理解,可以如此利用事務的commit和rollback方法:
SQL = "DELETE FROM Client WHERE level < %d" db = MySQLdb.connect(xxxxx) cursor = db.cursor() try: cursor.execute(SQL,(2,)) db.commit() except Exception,e: db.rollback() finally: cursor.close() db.close()
對於支持事務的數據庫, 在Python數據庫編程中,當游標建立之時,就自動開始了一個隱形的數據庫事務。commit()方法游標的所有更新操作,rollback()方法回滾當前游標的所有操作。
■ 積累
● 關於使用MySQLdb獲取到的數據的類型不符合預期的問題
今天碰到了一個問題。從數據庫中通過MySQLdb獲取到了一些數據是諸如這樣的((u'01',8L,Decimal(900.00)),)。可以看到MySQLdb取數據的時候對於相應的MySQL中的數據類型會被轉換成類似的Python中的類型。但是有時候我們不想要那么repr地表示,比如這一行數據我就只想讓它是'01',8,900.0這些比較基本的Python中的類型而不是unicode,long,float這些。
一種辦法是在取得數據之后進行一些數據的清洗。找到的另一種辦法是將建立連接時的convertor改變。
MySQLdb在建立和MySQL之間的連接的時候,會聲明好數據庫數據類型和Python數據類型的對應關系。這部分信息被維護在了MySQLdb.convertors.conversions這個字典里。重點關注這個字典的中間部分有一些類似於FIELD_TYPE.XXX: xxx的鍵值對。鍵值其實是一個常量,后者是Python中的一個類型。這個字典就是會在MySQLdb.connect方法被執行時作為一個參數傳遞進來,並憑借里面的信息來對應類型的。
所以如果我們想把默認從數據庫中取出來的Decimal換成float,8L換成int的8,就可以這么高:
from MySQLdb import convertors conv = convertors.conversions.copy() conv[246] = float # 246對應FIELD_TYPE.NEWDECIMAL,在convertors.py的代碼中,如果from decimal import Decimal沒有出錯那么這個類型的數據最終返回Decimal,現在改成了float conv[3] = int conv[4] = int # 3和4分別對應Long和LongLong數據,都改成int了 conn = MySQLdb.connect(host='xxxx',user='xxx',passwd='xxx',db='xxx',charset='xxx',conv=conv) # 將參數conv設置為我們修改過的字典,之后再進行常規操作即可