MYSQL Python 入門(mén)教程
(一)關(guān)于本教程
這是一本關(guān)于Python中使用Mysql編程的入門(mén)教程,它講述了Python中使用Mysql進(jìn)行編程的基本知識。主要使用MYSQLdb模塊。本教程中的所有實(shí)例是在ubuntu上開(kāi)發(fā)和測試的。本文由
(二)關(guān)于MYSQL數據庫
MYSQL是一個(gè)領(lǐng)先的開(kāi)源數據管理系統,是一個(gè)多用戶(hù)、多線(xiàn)程的數據庫系統。MYSQL在web應用中特別流行,是非常流行的LAMP(L-linux, A-apache, M-mysql, P-php)平臺中的一部分。MYSQL最早是由瑞典的MYSQL AB公司所開(kāi)發(fā), 這家公司以及Trolltech 是非常有名的開(kāi)放源代碼公司。MYSQL兼容大多數操作系統平臺,包括BSD Unix、Linux、Windows以及MAC。維基百科和YouTube使用MYSQL,這些網(wǎng)站每天處理上百萬(wàn)的查詢(xún)請求。MYSQL包括兩個(gè)版本:MYSQL服務(wù)端版本和MYSQL嵌入式版本。
(三)開(kāi)始前的準備
在本教材開(kāi)始之前,我們先搭建開(kāi)發(fā)環(huán)境。
如果你沒(méi)有安裝mysql數據庫,使用下面命令進(jìn)行安裝:
sudo apt-get install mysql-server
該命令安裝Mysql數據庫以及各種依賴(lài)庫,在安裝過(guò)程中,我們可以先想好Mysql數據庫的root密碼。
$ apt-cache search MySQLdb
python-mysqldb - A Python interface to MySQL
python-mysqldb-dbg - A Python interface to MySQL (debug extension)
bibus - bibliographic database
eikazo - graphical frontend for SANE designed for mass-scanning
如果我們不太清楚MYSQLdb模塊在哪個(gè)安裝包中,可以使用apt-cache search命令找到要具體的安裝包,如上所示,我們要安裝的是python-mysqldb模塊。使用下面命令安裝:
sudo apt-get install python-mysqldb
接下來(lái),我們使用mysqlclient建立一個(gè)新的數據庫以及數據庫用戶(hù),首先我們連接到myql數據庫中,如下所示:
$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 5.0.67-0ubuntu6 (Ubuntu)
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
+--------------------+
2 rows in set (0.00 sec)
然后創(chuàng )建數據庫testdb,命令如下:
mysql> CREATE DATABASE testdb;
Query OK, 1 row affected (0.02 sec)
最后我們創(chuàng )建一個(gè)'testuser'的測試用戶(hù),并予以相應的權限,命令如下:
mysql> CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'test623';
Query OK, 0 rows affected (0.00 sec)
mysql> USE testdb;
Database changed
mysql> GRANT ALL ON testdb.* TO 'testuser'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> quit;
Bye
至此,我們完成了開(kāi)發(fā)環(huán)境的搭建。
(四)_Mysql 模塊
_Mysql模塊實(shí)現了Mysql C API庫,但是它和python的DB API接口不兼容。一般來(lái)說(shuō),程序員更喜歡面向對象的Mysqldb模塊,Mysqldb后面的章節會(huì )詳細的講述。本節只給出_Mysql模塊的一個(gè)例子,代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import _mysql
import sys
con = None
try:
con = _mysql.connect('localhost', 'testuser',
'test623', 'testdb')
con.query("SELECT VERSION()")
result = con.use_result()
print "MySQL version: %s" % \
result.fetch_row()[0]
except _mysql.Error, e:
print "Error %d: %s" % (e.args[0], e.args[1])
sys.exit(1)
finally:
if con:
con.close()
(五)Mysqldb 模塊
MyqslDb是_Mysql模塊的輕度封裝,它兼容Python DB API接口,因此具有更好的移植性。使用MyqlDb進(jìn)行mysql編程是非常方便。
(六)第一個(gè)實(shí)例
在這個(gè)示例中,我們會(huì )打印Mysql的數據庫版本,代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
con = None
try:
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb');
cur = con.cursor()
cur.execute("SELECT VERSION()")
data = cur.fetchone()
print "Database version : %s " % data
except mdb.Error, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
finally:
if con:
con.close()
在上面的腳本中,我們連接到mysql數據庫中,并執行select version() 語(yǔ)句,該語(yǔ)句將返回mysql數據庫的當前版本,我們把它輸出到控制臺。
首先我們引入MysqlDB模塊,代碼如下:
import MySQLdb as mdb
然后初始化con變量為None,接著(zhù)鏈接到mysql數據庫,代碼如下:
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb');
Connect方法有四個(gè)參數,第一個(gè)參數是主機名,第二個(gè)參數是數據庫的用戶(hù)名,第三個(gè)參數是用戶(hù)名的密碼,最后一個(gè)參數是要鏈接的數據庫名。
cur = con.cursor()
cur.execute("SELECT VERSION()")
從con鏈接變量,我們獲取一個(gè)cur游標變量。游標是用來(lái)遍歷結果集中的記錄,我們調用游標的execute方法執行sql語(yǔ)句。
data = cur.fetchone()
我們取回數據,因為該結果集只有一行數據,所以為我們調用facthone方法。
print "Database version : %s " % data
調用print把結果輸出到屏幕上。
except mdb.Error, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
檢查數據庫錯誤是非常重要的,因為數據庫易于出現問(wèn)題的。
finally:
if con:
con.close()
最后關(guān)閉鏈接。
執行本腳本,可以得到類(lèi)似下面的輸出:
$ ./version.py
Database version : 5.5.9
(七)新建表并插入數據
示例代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
con = mdb.connect('localhost', 'testuser', 'test623', 'testdb');
with con:
cur = con.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS \
Writers(Id INT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(25))")
cur.execute("INSERT INTO Writers(Name) VALUES('Jack London')")
cur.execute("INSERT INTO Writers(Name) VALUES('Honore de Balzac')")
cur.execute("INSERT INTO Writers(Name) VALUES('Lion Feuchtwanger')")
cur.execute("INSERT INTO Writers(Name) VALUES('Emile Zola')")
cur.execute("INSERT INTO Writers(Name) VALUES('Truman Capote')")
我們建立一個(gè)Writers的表,并且插入了5條記錄。相關(guān)代碼如下:
cur.execute("CREATE TABLE IF NOT EXISTS \
Writers(Id INT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(25))")
cur.execute("INSERT INTO Writers(Name) VALUES('Jack London')")
通過(guò)執行腳本后,數據庫testdb中的輸入如下所示:
mysql> SELECT * FROM Writers;
+----+-------------------+
| Id | Name |
+----+-------------------+
| 1 | Jack London |
| 2 | Honore de Balzac |
| 3 | Lion Feuchtwanger |
| 4 | Emile Zola |
| 5 | Truman Capote |
+----+-------------------+
5 rows in set (0.00 sec)
(八)取回數據
上節我們在數據庫testddb中插入了5條記錄,本節將演示如何把這些數據取回來(lái)。本節所有代碼如下所示:
#!/usr/bin/python
# -*- coding: utf-8 -*
import MySQLdb as mdb
import sys
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb')
with con:
cur = con.cursor()
cur.execute("SELECT * FROM Writers")
rows = cur.fetchall()
for row in rows:
print row
以下代碼把表Writers中的所有數據都取回來(lái)。
rows = cur.fetchall()
Fetchall()函數將取回表中的所有記錄,返回一個(gè)結果集。它是一個(gè)元組的元組。元組內嵌的每個(gè)元組代表數據庫中的一行數據。
for row in rows:
print row
我們一行行的把數據打印到屏幕上。執行腳本,可以得到類(lèi)似一下的輸出:
$ ./retrieve.py
(1L, 'Jack London')
(2L, 'Honore de Balzac')
(3L, 'Lion Feuchtwanger')
(4L, 'Emile Zola')
(5L, 'Truman Capote')
一下子把所有數據全部取回來(lái)擴展性不是很好,我們改下程序,一行一行的從數據庫中讀取,代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb');
with con:
cur = con.cursor()
cur.execute("SELECT * FROM Writers")
numrows = int(cur.rowcount)
for i in range(numrows):
row = cur.fetchone()
print row[0], row[1]
首先我們游標的rowcount屬性獲取結果集中記錄的條數,然后使用fetchone方法一行行的把數據取回,并輸出到屏幕上。執行本腳本,可以得到一下類(lèi)似的輸出:
$ ./retrieve2.py
1 Jack London
2 Honore de Balzac
3 Lion Feuchtwanger
4 Emile Zola
5 Truman Capote
(九)字典游標
Mysqldb模塊中有很多種游標類(lèi)型,默認的游標以元組的元組方式返回數據。當我們使用字典游標時(shí),數據將以python中字典形式返回。這樣,我們就可以使用列名來(lái)引用數據了,本節代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb')
with con:
cur = con.cursor(mdb.cursors.DictCursor)
cur.execute("SELECT * FROM Writers")
rows = cur.fetchall()
for row in rows:
print "%s %s" % (row["Id"], row["Name"])
在上面代碼中,我們使用字典游標來(lái)操縱數據:
cur = con.cursor(mdb.cursors.DictCursor)
我們獲取所有數據,并且使用列名的方式獲取數據,輸出到屏幕上:
rows = cur.fetchall()
for row in rows:
print "%s %s" % (row["Id"], row["Name"])
(十)列名
下面示例代碼演示了如何打印表的列名,代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb')
with con:
cur = con.cursor()
cur.execute("SELECT * FROM Writers")
rows = cur.fetchall()
desc = cur.description
print "%s %3s" % (desc[0][0], desc[1][0])
for row in rows:
print "%2s %3s" % row
本例中,我們再次把writer表中的數據輸出到屏幕上,不過(guò)這次我們輸出了列名,列名是元數據,是cursor類(lèi)型的屬性:
desc = cur.description
Cursor類(lèi)型的description屬性查詢(xún)中的每一列的相關(guān)信息,我們使用以下語(yǔ)句打印出列名:
print "%s %3s" % (desc[0][0], desc[1][0])
整個(gè)程序輸出結果如下:
$ ./columnheaders.py
Id Name
1 Jack London
2 Honore de Balzac
3 Lion Feuchtwanger
4 Emile Zola
5 Truman Capote
(十一)格式化語(yǔ)句
在本節我們使用格式化語(yǔ)句,Python的Mysql DB接口支持5中不同的格式化方式,但MysqlDB模塊只支持其中的一種,即ANSI的printf格式化方式,代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
con = mdb.connect('localhost', 'testuser',
'test623', 'testdb')
with con:
cur = con.cursor()
cur.execute("UPDATE Writers SET Name = %s WHERE Id = %s",
("Guy de Maupasant", "4"))
print "Number of rows updated: %d" % cur.rowcount
通過(guò)如下代碼,我們id=4的作者的名字,
cur.execute("UPDATE Writers SET Name = %s WHERE Id = %s",
("Guy de Maupasant", "4"))
(十二)插入圖片
有人喜歡使用mysql來(lái)存儲圖片,而有的人喜歡把圖片存儲在文件系統中。而當我們要處理成千上萬(wàn)的圖片時(shí),會(huì )引起技術(shù)問(wèn)題。圖片時(shí)二進(jìn)制數據,mysql有種特殊的數據類(lèi)型,用來(lái)存儲二進(jìn)制數據,叫做BLOB(Binary Large Ojbect)。
開(kāi)始之前,我們創(chuàng )建一個(gè)images表用來(lái)存儲圖片數據,代碼如下:
mysql> CREATE TABLE Images(Id INT PRIMARY KEY AUTO_INCREMENT, Data MEDIUMBLOB);
Query OK, 0 rows affected (0.06 sec)
接著(zhù),我們讀取圖片數據,并把它插入到數據庫中,示例代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
try:
fin = open("chrome.png")
img = fin.read()
fin.close()
except IOError, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
try:
conn = mdb.connect(host='localhost',user='testuser',
passwd='test623', db='testdb')
cursor = conn.cursor()
cursor.execute("INSERT INTO Images SET Data='%s'" % \
mdb.escape_string(img))
conn.commit()
cursor.close()
conn.close()
except mdb.Error, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
首先,我們打開(kāi)一個(gè)圖片,并讀取圖片數據,代碼如下:
fin = open("chrome.png")
img = fin.read()
接著(zhù),我們把圖片數據插入到數據庫中,并使用escape_string進(jìn)行特殊字符串轉義。代碼如下:
cursor.execute("INSERT INTO Images SET Data='%s'" % \
mdb.escape_string(img))
(十三)讀取圖片
上一節中,我們把圖片存儲到數據庫中了,在本節,我們將取回并保存為圖片文件。本節示例如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
try:
conn = mdb.connect(host='localhost',user='testuser',
passwd='test623', db='testdb')
cursor = conn.cursor()
cursor.execute("SELECT Data FROM Images LIMIT 1")
fout = open('image.png','wb')
fout.write(cursor.fetchone()[0])
fout.close()
cursor.close()
conn.close()
except IOError, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
首先,我們從數據庫中讀取一張圖片數據:
cursor.execute("SELECT Data FROM Images LIMIT 1")
接著(zhù),我們以二進(jìn)制的寫(xiě)方式打開(kāi)一個(gè)文件,寫(xiě)入圖片數據:
fout = open('image.png','wb')
fout.write(cursor.fetchone()[0])
執行程序,我們當前目錄應該有一張圖片,驗證一下是否和寫(xiě)入數據庫之前的圖片一致。
(十四)事務(wù)支持
事務(wù)是數據庫中的原子操作,不管要操作的數據在一個(gè)或者多個(gè)數據中。事務(wù)中的所有sql語(yǔ)句的結果要么全部提交,要么全部回滾。
對于支持事務(wù)的數據庫, 在Python數據庫編程中,當游標建立之時(shí),就自動(dòng)開(kāi)始了一個(gè)隱形的數據庫事務(wù)。Commit()方法游標的所有更新操作,rollback()方法回滾當前游標的所有操作。每一個(gè)方法都開(kāi)始了一個(gè)新的事務(wù)。
Mysq數據庫有不同的存儲引擎,其中最知名的引擎是MyISAM和 InnoDb引擎。MyISAM是Mysql的默認引擎。這是在數據安全和性能之前尋求一個(gè)平衡。MysqlISAM引擎的表處理性能很高,但是不支持事務(wù)。而InnoDB引擎在數據丟失方面更安全,因為它支持事務(wù),但是相應的表處理比較慢。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
try:
conn = mdb.connect('localhost', 'testuser',
'test623', 'testdb');
cursor = conn.cursor()
cursor.execute("UPDATE Writers SET Name = %s WHERE Id = %s",
("Leo Tolstoy", "1"))
cursor.execute("UPDATE Writers SET Name = %s WHERE Id = %s",
("Boris Pasternak", "2"))
cursor.execute("UPDATE Writer SET Name = %s WHERE Id = %s",
("Leonid Leonov", "3"))
conn.commit()
cursor.close()
conn.close()
except mdb.Error, e:
conn.rollback()
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
以上代碼我們嘗試更新三條記錄,記住,Writers表的存儲引擎是MyISAM,開(kāi)始我們更新id等于1和2 的記錄,代碼如下:
cursor.execute("UPDATE Writers SET Name = %s WHERE Id = %s",
("Leo Tolstoy", "1"))
cursor.execute("UPDATE Writers SET Name = %s WHERE Id = %s",
("Boris Pasternak", "2"))
然后我們更新id等于3的記錄,但是我們相應的sql語(yǔ)句有詞法錯誤,代碼如下:
cursor.execute("UPDATE Writer SET Name = %s WHERE Id = %s",
("Leonid Leonov", "3"))
出現錯誤時(shí),我們調用rollback(),但是它沒(méi)有做任何事情:
conn.rollback()
我們執行腳本,遇到一個(gè)錯誤:
$ ./isam.py
Error 1146: Table 'testdb.Writer' doesn't exist
mysql> SELECT * FROM Writers;
+----+-------------------+
| Id | Name |
+----+-------------------+
| 1 | Leo Tolstoy |
| 2 | Boris Pasternak |
| 3 | Lion Feuchtwanger |
| 4 | Guy de Maupasant |
| 5 | Truman Capote |
+----+-------------------+
5 rows in set (0.00 sec)
但是Id=1和2的記錄已經(jīng)更新了,說(shuō)明rollback并沒(méi)有回滾。
在本章最后一個(gè)示例中,我們將重建writers表,這次我們使用InnoDB作為writers的存儲引擎,InnoDB存儲引擎支持事務(wù),重建代碼如下:
DROP TABLE Writers;
CREATE TABLE IF NOT EXISTS Writers(Id INT PRIMARY KEY AUTO_INCREMENT,
Name VARCHAR(25)) ENGINE=INNODB;
INSERT INTO Writers(Name) VALUES('Jack London');
INSERT INTO Writers(Name) VALUES('Honore de Balzac');
INSERT INTO Writers(Name) VALUES('Lion Feuchtwanger');
INSERT INTO Writers(Name) VALUES('Emile Zola');
INSERT INTO Writers(Name) VALUES('Truman Capote');
我們執行下面的腳本,用來(lái)驗證InnoDB的事務(wù)機制,代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb as mdb
import sys
try:
conn = mdb.connect('localhost', 'testuser',
'test623', 'testdb');
cursor = conn.cursor()
cursor.execute("DELETE FROM Writers WHERE Id = 5")
cursor.execute("DELETE FROM Writers WHERE Id = 4")
cursor.execute("DELETE FROM Writer WHERE Id = 3")
conn.commit()
except mdb.Error, e:
conn.rollback()
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
cursor.close()
conn.close()
我們刪除表中的三行數據,為了驗證事務(wù)機制,我們的第三個(gè)sql語(yǔ)句存在語(yǔ)法錯誤,執行結果類(lèi)似下面輸出:
$ ./innodb.py
Error 1146: Table 'testdb.Writer' doesn't exist
mysql> SELECT * FROM Writers;
+----+-------------------+
| Id | Name |
+----+-------------------+
| 1 | Jack London |
| 2 | Honore de Balzac |
| 3 | Lion Feuchtwanger |
| 4 | Emile Zola |
| 5 | Truman Capote |
+----+-------------------+
5 rows in set (0.00 sec)
Sql錯誤在我們commit之前發(fā)生,錯誤處理程序調用rollback()回滾,通過(guò)驗證我們發(fā)現數據庫并沒(méi)有更改。
聯(lián)系客服