MySQLdb呢,其實和Python內置的sqlite3的使用方法基本相同。
警告:
不要使用字符串拼接生成SQL語句,否則可能產生SQL注入的問題。應當使用 execute() 的第二個參數檢查輸入的合法性。
#do NOT do this! cmd = "update people set name='%s' where id='%s'" % (name, id)
cur.execute(cmd) # instead, do this: cmd = "update people set name=%s where id=%s"
cur.execute(cmd, (name, id))
采用的是MySQLdb操作的MYSQL數據庫。先來一個簡單的例子吧:
import MySQLdb try: conn=MySQLdb.connect(host='localhost',user='root',passwd='mysql',db='test',port=3306) cur=conn.cursor() cur.execute('select * from user') cur.close() conn.close() except MySQLdb.Error,e: print "Mysql Error %d: %s" % (e.args[0], e.args[1])
請注意修改你的數據庫,主機名,用戶名,密碼。
下面來大致演示一下插入數據,批量插入數據,更新數據的例子吧:
import MySQLdb try: conn=MySQLdb.connect(host='localhost',user='root',passwd='root',port=3306) cur=conn.cursor() cur.execute('create database if not exists python') conn.select_db('python') cur.execute('create table test(id int,info varchar(20))') value=[1,'hi rollen'] cur.execute('insert into test values(%s,%s)',value) values=[] for i in range(20): values.append((i,'hi rollen'+str(i))) cur.executemany('insert into test values(%s,%s)',values) cur.execute('update test set info="I am rollen" where id=3') conn.commit() cur.close() conn.close() except MySQLdb.Error,e: print "Mysql Error %d: %s" % (e.args[0], e.args[1])
游標相當於是集合中元素的指針,SQL查詢結果是一個集合,而線程每次只能獲得一個元素的引用。游標也必須要關閉,否則會占用有限的資源。
有些界面可以自動提交。但是對於python的MySQLdb模塊,必須要調用commit(), 否則所有的更新只對於當前連接有效,數據庫並不會實際被更改。
每插入一次就要commit一次! 具體見本文最后。
import MySQLdb try: conn=MySQLdb.connect(host='localhost',user='root',passwd='root',port=3306) cur=conn.cursor() conn.select_db('python') count=cur.execute('select * from test') print 'there has %s rows record' % count result=cur.fetchone() print result print 'ID: %s info %s' % result results=cur.fetchmany(5) for r in results: print r print '=='*10 cur.scroll(0,mode='absolute') results=cur.fetchall() for r in results: print r[1] conn.commit() cur.close() conn.close() except MySQLdb.Error,e: print "Mysql Error %d: %s" % (e.args[0], e.args[1])
查詢后中文會正確顯示,但在數據庫中卻是亂碼的。
網上的說法是加一個屬性,不過經過本人實驗,這並不能解決問題,反而讓打印出來的中文全是問號。
在Python代碼
conn = MySQLdb.Connect(host='localhost', user='root', passwd='root', db='python') 中加一個屬性:
改為:
conn = MySQLdb.Connect(host='localhost', user='root', passwd='root', db='python',charset='utf8')
charset是要跟你數據庫的編碼一樣,如果是數據庫是gb2312 ,則寫charset='gb2312'。
常用函數
下面貼一下常用的函數:
然后,這個連接對象也提供了對事務操作的支持,標准的方法
commit() 提交
rollback() 回滾
cursor用來執行命令的方法:
callproc(self, procname, args):用來執行存儲過程,接收的參數為存儲過程名和參數列表,返回值為受影響的行數
execute(self, query, args):執行單條sql語句,接收的參數為sql語句本身和使用的參數列表,返回值為受影響的行數
executemany(self, query, args):執行單挑sql語句,但是重復執行參數列表里的參數,返回值為受影響的行數
nextset(self):移動到下一個結果集
cursor用來接收返回值的方法:
fetchall(self):接收全部的返回結果行.
fetchmany(self, size=None):接收size條返回結果行.如果size的值大於返回的結果行的數量,則會返回cursor.arraysize條數據.
fetchone(self):返回一條結果行.
scroll(self, value, mode='relative'):移動指針到某一行.如果mode='relative',則表示從當前所在行移動value條,如果 mode='absolute',則表示從結果集的第一行移動value條.
字典而非元組
MySQLdb默認情況下,查詢結果行都是返回tuple,訪問的時候不是很方便,必須按照0,1這樣讀取。
使用sqllite3的時候,可以修改過Connection對象的row_factory屬性,以便使用sqlite3.Row,這樣結果集中的數據行就是字典形式的,可以用字段名訪問,那么MySQLdb中是不是也有這樣的方法呢?MySQLdb中有DictCursor,要做到這點也很簡單,那就是建立數據庫連接是傳遞cusorclass參數,或者在獲取Cursor對象時傳遞cusorclass參數即可:
conn=MySQLdb.connect(host="localhost",user="root",passwd="root",db="test",charset="utf8",cursorclass=MySQLdb.cursors.DictCursor)
cursor = conn.cursor()
或者
conn=MySQLdb.connect(host="localhost",user="root",passwd="root",db="test",charset="utf8")
cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
返回結果就是這樣:
{'name': u'ccc', 'created': 33L}
{'name': u'ddd', 'created': 44L}
{'name': u'zzz', 'created': 1340790602L}
MySQL中的事務
事務支持
首先要了解到,Innodb支持事務, MyISAM不支持事務。
而且mysql的事務是默認是打開autocommit的,但是我們使用的python庫,mysqldb卻是默認關閉autocommit,所以你需要自己去commit,自己去rollback。
回到問題
任何時候,在執行提交或者回滾操作之前,所有的操作都會被數據庫認為屬於同一個事務,
MySQL事務的默認隔離級別是repeatable read(重復讀),而這卻會引起phantom read(幻想讀)。
幻像讀(phantom read):在同一事務中,同一查詢多次進行時候,由於其他插入操作(insert)的事務提交,導致每次返回不同的結果集。
而innodb為了防止幻讀,會在一個事務中,使所有select的結果保持與第一次select時的snapshot一致,這樣其他事務的插入是不會被感知到的。
所以對於一個只有讀的事務,我們也應該及時提交后再讀,使snapshot刷新。
