# Python CGI編程
## 什么是CGI
CGI 目前由NCSA維護,NCSA定義CGI如下:
CGI(Common Gateway Interface),通用網關接口,它是一段程序,運行在服務器上如:HTTP服務器,提供同客戶端HTML頁面的接口。
## 網頁瀏覽
為了更好的了解CGI是如何工作的,我們可以從在網頁上點擊一個鏈接或URL的流程:
* 1、使用你的瀏覽器訪問URL并連接到HTTP web 服務器。
* 2、Web服務器接收到請求信息后會解析URL,并查找訪問的文件在服務器上是否存在,如果存在返回文件的內容,否則返回錯誤信息。
* 3、瀏覽器從服務器上接收信息,并顯示接收的文件或者錯誤信息。
CGI程序可以是Python腳本,PERL腳本,SHELL腳本,C或者C++程序等。
## CGI架構圖

## Web服務器支持及配置
在你進行CGI編程前,確保您的Web服務器支持CGI及已經配置了CGI的處理程序。
所有的HTTP服務器執行CGI程序都保存在一個預先配置的目錄。這個目錄被稱為CGI目錄,并按照慣例,它被命名為/var/www/cgi-bin目錄。
CGI文件的擴展名為.cgi,python也可以使用.py擴展名。
默認情況下,Linux服務器配置運行的cgi-bin目錄中為/var/www。
如果你想指定其他運行CGI腳本的目錄,可以修改httpd.conf配置文件,如下所示:
```
<Directory "/var/www/cgi-bin">
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/cgi-bin">
Options All
</Directory>
```
## 第一個CGI程序
我們使用Python創建第一個CGI程序,文件名為hellp.py,文件位于/var/www/cgi-bin目錄中,內容如下,修改文件的權限為755:
```
#!/usr/bin/python
print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Hello Word - First CGI Program</title>'
print '</head>'
print '<body>'
print '<h2>Hello Word! This is my first CGI program</h2>'
print '</body>'
print '</html>'
```
以上程序在瀏覽器訪問顯示結果如下:
```
Hello Word! This is my first CGI program
```
這個的hello.py腳本是一個簡單的Python腳本,腳本第一的輸出內容"Content-type:text/html\r\n\r\n"發送到瀏覽器并告知瀏覽器顯示的內容類型為"text/html"。
## HTTP頭部
hello.py文件內容中的" Content-type:text/html\r\n\r\n"即為HTTP頭部的一部分,它會發送給瀏覽器告訴瀏覽器文件的內容類型。
HTTP頭部的格式如下:
```
HTTP 字段名: 字段內容
例如
Content-type: text/html\r\n\r\n
```
以下表格介紹了CGI程序中HTTP頭部經常使用的信息:
| 頭 | 描述 |
| --- | --- |
| Content-type: | 請求的與實體對應的MIME信息。例如: Content-type:text/html |
| Expires: Date | 響應過期的日期和時間 |
| Location: URL | 用來重定向接收方到非請求URL的位置來完成請求或標識新的資源 |
| Last-modified: Date | 請求資源的最后修改時間 |
| Content-length: N | 請求的內容長度 |
| Set-Cookie: String | 設置Http Cookie |
## CGI環境變量
所有的CGI程序都接收以下的環境變量,這些變量在CGI程序中發揮了重要的作用:
| 變量名 | 描述 |
| --- | --- |
| CONTENT_TYPE | 這個環境變量的值指示所傳遞來的信息的MIME類型。目前,環境變量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示數據來自于HTML表單。 |
| CONTENT_LENGTH | 如果服務器與CGI程序信息的傳遞方式是POST,這個環境變量即使從標準輸入STDIN中可以讀到的有效數據的字節數。這個環境變量在讀取所輸入的數據時必須使用。 |
| HTTP_COOKIE | 客戶機內的 COOKIE 內容。 |
| HTTP_USER_AGENT | 提供包含了版本數或其他專有數據的客戶瀏覽器信息。 |
| PATH_INFO | 這個環境變量的值表示緊接在CGI程序名之后的其他路徑信息。它常常作為CGI程序的參數出現。 |
| QUERY_STRING | 如果服務器與CGI程序信息的傳遞方式是GET,這個環境變量的值即使所傳遞的信息。這個信息經跟在CGI程序名的后面,兩者中間用一個問號'?'分隔。 |
| REMOTE_ADDR | 這個環境變量的值是發送請求的客戶機的IP地址,例如上面的192.168.1.67。這個值總是存在的。而且它是Web客戶機需要提供給Web服務器的唯一標識,可以在CGI程序中用它來區分不同的Web客戶機。 |
| REMOTE_HOST | 這個環境變量的值包含發送CGI請求的客戶機的主機名。如果不支持你想查詢,則無需定義此環境變量。 |
| REQUEST_METHOD | 提供腳本被調用的方法。對于使用 HTTP/1.0 協議的腳本,僅 GET 和 POST 有意義。 |
| SCRIPT_FILENAME | CGI腳本的完整路徑 |
| SCRIPT_NAME | CGI腳本的的名稱 |
| SERVER_NAME | 這是你的 WEB 服務器的主機名、別名或IP地址。 |
| SERVER_SOFTWARE | 這個環境變量的值包含了調用CGI程序的HTTP服務器的名稱和版本號。例如,上面的值為Apache/2.2.14(Unix) |
以下是一個簡單的CGI腳本輸出CGI的環境變量:
```
#!/usr/bin/python
import os
print "Content-type: text/html\r\n\r\n";
print "Environment<\br>";
for param in os.environ.keys():
print "<b>%20s</b>: %s<\br>" % (param, os.environ[param])
```
## GET和POST方法
瀏覽器客戶端通過兩種方法向服務器傳遞信息,這兩種方法就是 GET 方法和 POST 方法。
### 使用GET方法傳輸數據
GET方法發送編碼后的用戶信息到服務端,數據信息包含在請求頁面的URL上,以"?"號分割, 如下所示:
```
http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2
```
有關 GET 請求的其他一些注釋:
* GET 請求可被緩存
* GET 請求保留在瀏覽器歷史記錄中
* GET 請求可被收藏為書簽
* GET 請求不應在處理敏感數據時使用
* GET 請求有長度限制
* GET 請求只應當用于取回數據
### 簡單的url實例:GET方法
以下是一個簡單的URL,使用GET方法向hello_get.py程序發送兩個參數:
```
/cgi-bin/hello_get.py?first_name=ZARA&last_name=ALI
```
以下為hello_get.py文件的代碼:
```
#!/usr/bin/python
# CGI處理模塊
import cgi, cgitb
# 創建 FieldStorage 的實例化
form = cgi.FieldStorage()
# 獲取數據
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"
```
瀏覽器請求輸出結果:
```
Hello ZARA ALI
```
### 簡單的表單實例:GET方法
以下是一個通過HTML的表單使用GET方法向服務器發送兩個數據,提交的服務器腳本同樣是hello_get.py文件,代碼如下:
```
<form action="/cgi-bin/hello_get.py" method="get">
First Name: <input type="text" name="first_name"> <br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
```
### 使用POST方法傳遞數據
使用POST方法向服務器傳遞數據是更安全可靠的,像一些敏感信息如用戶密碼等需要使用POST傳輸數據。
以下同樣是hello_get.py ,它也可以處理瀏覽器提交的POST表單數據:
```
#!/usr/bin/python
# 引入 CGI 模塊
import cgi, cgitb
# 創建 FieldStorage 實例
form = cgi.FieldStorage()
# 獲取表單數據
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"
```
以下為表單通過POST方法向服務器腳本hello_get.py提交數據:
```
<form action="/cgi-bin/hello_get.py" method="post">
First Name: <input type="text" name="first_name"><br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
```
### 通過CGI程序傳遞checkbox數據
checkbox用于提交一個或者多個選項數據,HTML代碼如下:
```
<form action="/cgi-bin/checkbox.cgi" method="POST" target="_blank">
<input type="checkbox" name="maths" value="on" /> Maths
<input type="checkbox" name="physics" value="on" /> Physics
<input type="submit" value="Select Subject" />
</form>
```
以下為 checkbox.cgi 文件的代碼:
```
#!/usr/bin/python
# 引入 CGI 處理模塊
import cgi, cgitb
# 創建 FieldStorage的實例
form = cgi.FieldStorage()
# 接收字段數據
if form.getvalue('maths'):
math_flag = "ON"
else:
math_flag = "OFF"
if form.getvalue('physics'):
physics_flag = "ON"
else:
physics_flag = "OFF"
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Checkbox - Third CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> CheckBox Maths is : %s</h2>" % math_flag
print "<h2> CheckBox Physics is : %s</h2>" % physics_flag
print "</body>"
print "</html>"
```
### 通過CGI程序傳遞Radio數據
Radio只向服務器傳遞一個數據,HTML代碼如下:
```
<form action="/cgi-bin/radiobutton.py" method="post" target="_blank">
<input type="radio" name="subject" value="maths" /> Maths
<input type="radio" name="subject" value="physics" /> Physics
<input type="submit" value="Select Subject" />
</form>
```
radiobutton.py 腳本代碼如下:
```
#!/usr/bin/python
# Import modules for CGI handling
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
if form.getvalue('subject'):
subject = form.getvalue('subject')
else:
subject = "Not set"
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Radio - Fourth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"
```
### 通過CGI程序傳遞 Textarea 數據
Textarea向服務器傳遞多行數據,HTML代碼如下:
```
<form action="/cgi-bin/textarea.py" method="post" target="_blank">
<textarea name="textcontent" cols="40" rows="4">
Type your text here...
</textarea>
<input type="submit" value="Submit" />
</form>
```
textarea.cgi腳本代碼如下:
```
#!/usr/bin/python
# Import modules for CGI handling
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
if form.getvalue('textcontent'):
text_content = form.getvalue('textcontent')
else:
text_content = "Not entered"
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>";
print "<title>Text Area - Fifth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Entered Text Content is %s</h2>" % text_content
print "</body>"
```
### 通過CGI程序傳遞下拉數據
HTML下拉框代碼如下:
```
<form action="/cgi-bin/dropdown.py" method="post" target="_blank">
<select name="dropdown">
<option value="Maths" selected>Maths</option>
<option value="Physics">Physics</option>
</select>
<input type="submit" value="Submit"/>
</form>
```
dropdown.py 腳本代碼如下所示:
```
#!/usr/bin/python
# Import modules for CGI handling
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
if form.getvalue('dropdown'):
subject = form.getvalue('dropdown')
else:
subject = "Not entered"
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Dropdown Box - Sixth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"
```
## CGI中使用Cookie
在http協議一個很大的缺點就是不作用戶身份的判斷,這樣給編程人員帶來很大的不便,
而cookie功能的出現彌補了這個缺憾。
所有cookie就是在客戶訪問腳本的同時,通過客戶的瀏覽器,在客戶硬盤上寫入紀錄數據 ,當下次客戶訪問腳本時取回數據信息,從而達到身份判別的功能,cookie常用在密碼判斷中 。
### cookie的語法
http cookie的發送是通過http頭部來實現的,他早于文件的傳遞,頭部set-cookie的語法如下:
```
Set-cookie:name=name;expires=date;path=path;domain=domain;secure
```
* name=name: 需要設置cookie的值(name不能使用";"和","號),有多個name值時用";"分隔例如:name1=name1;name2=name2;name3=name3。
* expires=date: cookie的有效期限,格式: expires="Wdy,DD-Mon-YYYY HH:MM:SS"
* path=path: 設置cookie支持的路徑,如果path是一個路徑,則cookie對這個目錄下的所有文件及子目錄生效,例如: path="/cgi-bin/",如果path是一個文件,則cookie指對這個文件生效,例如:path="/cgi-bin/cookie.cgi"。
* domain=domain: 對cookie生效的域名,例如:domain="www.chinalb.com"
* secure: 如果給出此標志,表示cookie只能通過SSL協議的https服務器來傳遞。
* cookie的接收是通過設置環境變量HTTP_COOKIE來實現的,CGI程序可以通過檢索該變量獲取cookie信息。
## Cookie設置
Cookie的設置非常簡單,cookie會在http頭部單獨發送。以下實例在cookie中設置了UserID 和 Password:
```
<pre>
#!/usr/bin/python
print "Set-Cookie:UserID=XYZ;\r\n"
print "Set-Cookie:Password=XYZ123;\r\n"
print "Set-Cookie:Expires=Tuesday, 31-Dec-2007 23:12:40 GMT";\r\n"
print "Set-Cookie:Domain=www.w3cschool.cc;\r\n"
print "Set-Cookie:Path=/perl;\n"
print "Content-type:text/html\r\n\r\n"
...........Rest of the HTML Content....
```
以上實例使用了 Set-Cookie 頭信息來設置Cookie信息,可選項中設置了Cookie的其他屬性,如過期時間Expires,域名Domain,路徑Path。這些信息設置在 "Content-type:text/html\r\n\r\n"之前。
## 檢索Cookie信息
Cookie信息檢索頁非常簡單,Cookie信息存儲在CGI的環境變量HTTP_COOKIE中,存儲格式如下:
```
key1=value1;key2=value2;key3=value3....
```
以下是一個簡單的CGI檢索cookie信息的程序:
```
#!/usr/bin/python
# Import modules for CGI handling
from os import environ
import cgi, cgitb
if environ.has_key('HTTP_COOKIE'):
for cookie in map(strip, split(environ['HTTP_COOKIE'], ';')):
(key, value ) = split(cookie, '=');
if key == "UserID":
user_id = value
if key == "Password":
password = value
print "User ID = %s" % user_id
print "Password = %s" % password
```
以上腳本輸出結果如下:
```
User ID = XYZ
Password = XYZ123
```
文件上傳實例:
HTML設置上傳文件的表單需要設置enctype 屬性為multipart/form-data,代碼如下所示:
```
<html>
<body>
<form enctype="multipart/form-data"
action="save_file.py" method="post">
<p>File: <input type="file" name="filename" /></p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
```
save_file.py腳本文件代碼如下:
```
#!/usr/bin/python
import cgi, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
# 獲取文件名
fileitem = form['filename']
# 檢測文件是否上傳
if fileitem.filename:
# 設置文件路徑
fn = os.path.basename(fileitem.filename)
open('/tmp/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print """\
Content-Type: text/html\n
<html>
<body>
<p>%s</p>
</body>
</html>
""" % (message,)
```
如果你使用的系統是Unix/Linux,你必須替換文件分隔符,在window下只需要使用open()語句即可:
```
fn = os.path.basename(fileitem.filename.replace("\\", "/" ))
```
## 文件下載對話框
如果我們需要為用戶提供文件下載鏈接,并在用戶點擊鏈接后彈出文件下載對話框,我們通過設置HTTP頭信息來實現這些功能,功能代碼如下:
```
#!/usr/bin/python
# HTTP Header
print "Content-Type:application/octet-stream; name=\"FileName\"\r\n";
print "Content-Disposition: attachment; filename=\"FileName\"\r\n\n";
# Actual File Content will go hear.
fo = open("foo.txt", "rb")
str = fo.read();
print str
# Close opend file
fo.close()
```
# python操作mysql數據庫
Python 標準數據庫接口為 Python DB-API,Python DB-API為開發人員提供了數據庫應用編程接口。
Python 數據庫接口支持非常多的數據庫,你可以選擇適合你項目的數據庫:
* GadFly
* mSQL
* MySQL
* PostgreSQL
* Microsoft SQL Server 2000
* Informix
* Interbase
* Oracle
* Sybase
你可以訪問[Python數據庫接口及API](https://wiki.python.org/moin/DatabaseInterfaces)查看詳細的支持數據庫列表。
不同的數據庫你需要下載不同的DB API模塊,例如你需要訪問Oracle數據庫和Mysql數據,你需要下載Oracle和MySQL數據庫模塊。
DB-API 是一個規范. 它定義了一系列必須的對象和數據庫存取方式, 以便為各種各樣的底層數據庫系統和多種多樣的數據庫接口程序提供一致的訪問接口 。
Python的DB-API,為大多數的數據庫實現了接口,使用它連接各數據庫后,就可以用相同的方式操作各數據庫。
Python DB-API使用流程:
* 引入 API 模塊。
* 獲取與數據庫的連接。
* 執行SQL語句和存儲過程。
* 關閉數據庫連接。
## 什么是MySQLdb?
MySQLdb 是用于Python鏈接Mysql數據庫的接口,它實現了 Python 數據庫 API 規范 V2.0,基于 MySQL C API 上建立的。
## 如何安裝MySQLdb?
為了用DB-API編寫MySQL腳本,必須確保已經安裝了MySQL。復制以下代碼,并執行:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
```
如果執行后的輸出結果如下所示,意味著你沒有安裝 MySQLdb 模塊:
```
Traceback (most recent call last):
File "test.py", line 3, in <module>
import MySQLdb
ImportError: No module named MySQLdb
```
安裝MySQLdb,請訪問 [http://sourceforge.net/projects/mysql-python](//sourceforge.net/projects/mysql-python) ,(Linux平臺可以訪問:[https://pypi.python.org/pypi/MySQL-python](https://pypi.python.org/pypi/MySQL-python))從這里可選擇適合您的平臺的安裝包,分為預編譯的二進制文件和源代碼安裝包。
如果您選擇二進制文件發行版本的話,安裝過程基本安裝提示即可完成。如果從源代碼進行安裝的話,則需要切換到MySQLdb發行版本的頂級目錄,并鍵入下列命令:
```
$ gunzip MySQL-python-1.2.2.tar.gz
$ tar -xvf MySQL-python-1.2.2.tar
$ cd MySQL-python-1.2.2
$ python setup.py build
$ python setup.py install
```
**注意:**請確保您有root權限來安裝上述模塊。
## 數據庫連接
連接數據庫前,請先確認以下事項:
* 您已經創建了數據庫 TESTDB.
* 在TESTDB數據庫中您已經創建了表 EMPLOYEE
* EMPLOYEE表字段為 FIRST_NAME, LAST_NAME, AGE, SEX 和 INCOME。
* 連接數據庫TESTDB使用的用戶名為 "testuser" ,密碼為 "test123",你可以可以自己設定或者直接使用root用戶名及其密碼,Mysql數據庫用戶授權請使用Grant命令。
* 在你的機子上已經安裝了 Python MySQLdb 模塊。
* 如果您對sql語句不熟悉,可以訪問我們的 [SQL基礎教程](/sql/sql-tutorial.html)
### 實例:
以下實例鏈接Mysql的TESTDB數據庫:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
# 打開數據庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# 使用execute方法執行SQL語句
cursor.execute("SELECT VERSION()")
# 使用 fetchone() 方法獲取一條數據庫。
data = cursor.fetchone()
print "Database version : %s " % data
# 關閉數據庫連接
db.close()
```
執行以上腳本輸出結果如下:
```
Database version : 5.0.45
```
## 創建數據庫表
如果數據庫連接存在我們可以使用execute()方法來為數據庫創建表,如下所示創建表EMPLOYEE:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
# 打開數據庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# 如果數據表已經存在使用 execute() 方法刪除表。
cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
# 創建數據表SQL語句
sql = """CREATE TABLE EMPLOYEE (
FIRST_NAME CHAR(20) NOT NULL,
LAST_NAME CHAR(20),
AGE INT,
SEX CHAR(1),
INCOME FLOAT )"""
cursor.execute(sql)
# 關閉數據庫連接
db.close()
```
## 數據庫插入操作
以下實例使用執行 SQL INSERT 語句向表 EMPLOYEE 插入記錄:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
# 打開數據庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 插入語句
sql = """INSERT INTO EMPLOYEE(FIRST_NAME,
LAST_NAME, AGE, SEX, INCOME)
VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""
try:
# 執行sql語句
cursor.execute(sql)
# 提交到數據庫執行
db.commit()
except:
# Rollback in case there is any error
db.rollback()
# 關閉數據庫連接
db.close()
```
以上例子也可以寫成如下形式:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
# 打開數據庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 插入語句
sql = "INSERT INTO EMPLOYEE(FIRST_NAME, \
LAST_NAME, AGE, SEX, INCOME) \
VALUES ('%s', '%s', '%d', '%c', '%d' )" % \
('Mac', 'Mohan', 20, 'M', 2000)
try:
# 執行sql語句
cursor.execute(sql)
# 提交到數據庫執行
db.commit()
except:
# 發生錯誤時回滾
db.rollback()
# 關閉數據庫連接
db.close()
```
### 實例:
以下代碼使用變量向SQL語句中傳遞參數:
```
..................................
user_id = "test123"
password = "password"
con.execute('insert into Login values("%s", "%s")' % \
(user_id, password))
..................................
```
## 數據庫查詢操作
Python查詢Mysql使用 fetchone() 方法獲取單條數據, 使用fetchall() 方法獲取多條數據。
* **fetchone():** 該方法獲取下一個查詢結果集。結果集是一個對象
* **fetchall():**接收全部的返回結果行.
* **rowcount:** 這是一個只讀屬性,并返回執行execute()方法后影響的行數。
### 實例:
查詢EMPLOYEE表中salary(工資)字段大于1000的所有數據:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
# 打開數據庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 查詢語句
sql = "SELECT * FROM EMPLOYEE \
WHERE INCOME > '%d'" % (1000)
try:
# 執行SQL語句
cursor.execute(sql)
# 獲取所有記錄列表
results = cursor.fetchall()
for row in results:
fname = row[0]
lname = row[1]
age = row[2]
sex = row[3]
income = row[4]
# 打印結果
print "fname=%s,lname=%s,age=%d,sex=%s,income=%d" % \
(fname, lname, age, sex, income )
except:
print "Error: unable to fecth data"
# 關閉數據庫連接
db.close()
```
以上腳本執行結果如下:
```
fname=Mac, lname=Mohan, age=20, sex=M, income=2000
```
## 數據庫更新操作
更新操作用于更新數據表的的數據,以下實例將 TESTDB表中的 SEX 字段全部修改為 'M',AGE 字段遞增1:
```
# encoding: utf-8
#!/usr/bin/python
import MySQLdb
# 打開數據庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 更新語句
sql = "UPDATE EMPLOYEE SET AGE = AGE + 1
WHERE SEX = '%c'" % ('M')
try:
# 執行SQL語句
cursor.execute(sql)
# 提交到數據庫執行
db.commit()
except:
# 發生錯誤時回滾
db.rollback()
# 關閉數據庫連接
db.close()
```
### 執行事務
事務機制可以確保數據一致性。
事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為ACID特性。
* 原子性(atomicity)。一個事務是一個不可分割的工作單位,事務中包括的諸操作要么都做,要么都不做。
* 一致性(consistency)。事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。
* 隔離性(isolation)。一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對并發的其他事務是隔離的,并發執行的各個事務之間不能互相干擾。
* 持久性(durability)。持續性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。
Python DB API 2.0 的事務提供了兩個方法 commit 或 rollback。
### 實例:
```
# SQL刪除記錄語句
sql = "DELETE FROM EMPLOYEE WHERE AGE > '%d'" % (20)
try:
# 執行SQL語句
cursor.execute(sql)
# 向數據庫提交
db.commit()
except:
# 發生錯誤時回滾
db.rollback()
```
對于支持事務的數據庫, 在Python數據庫編程中,當游標建立之時,就自動開始了一個隱形的數據庫事務。
commit()方法游標的所有更新操作,rollback()方法回滾當前游標的所有操作。每一個方法都開始了一個新的事務。
## 錯誤處理
DB API中定義了一些數據庫操作的錯誤及異常,下表列出了這些錯誤和異常:
| 異常 | 描述 |
| --- | --- |
| Warning | 當有嚴重警告時觸發,例如插入數據是被截斷等等。必須是 StandardError 的子類。 |
| Error | 警告以外所有其他錯誤類。必須是 StandardError 的子類。 |
| InterfaceError | 當有數據庫接口模塊本身的錯誤(而不是數據庫的錯誤)發生時觸發。 必須是Error的子類。 |
| DatabaseError | 和數據庫有關的錯誤發生時觸發。 必須是Error的子類。 |
| DataError | 當有數據處理時的錯誤發生時觸發,例如:除零錯誤,數據超范圍等等。 必須是DatabaseError的子類。 |
| OperationalError | 指非用戶控制的,而是操作數據庫時發生的錯誤。例如:連接意外斷開、 數據庫名未找到、事務處理失敗、內存分配錯誤等等操作數據庫是發生的錯誤。 必須是DatabaseError的子類。 |
| IntegrityError | 完整性相關的錯誤,例如外鍵檢查失敗等。必須是DatabaseError子類。 |
| InternalError | 數據庫的內部錯誤,例如游標(cursor)失效了、事務同步失敗等等。 必須是DatabaseError子類。 |
| ProgrammingError | 程序錯誤,例如數據表(table)沒找到或已存在、SQL語句語法錯誤、 參數數量錯誤等等。必須是DatabaseError的子類。 |
| NotSupportedError | 不支持錯誤,指使用了數據庫不支持的函數或API等。例如在連接對象上 使用.rollback()函數,然而數據庫并不支持事務或者事務已關閉。 必須是DatabaseError的子類。 |
- Python 基礎教程
- Python 簡介
- Python 環境搭建
- Python 基礎語法
- Python 變量類型
- Python 運算符
- Python 條件語句
- Python 循環語句
- Python While循環語句
- Python for 循環語句
- Python 循環嵌套
- Python break 語句
- Python continue 語句
- Python pass 語句
- Python 數字
- Python 字符串
- Python 列表(Lists)
- Python 元組
- Python 字典(Dictionary)
- Python 日期和時間
- Python 函數
- Python 模塊
- Python 文件I/O
- Python 異常處理
- Python 高級教程
- Python 面向對象
- Python 正則表達式
- Python CGI編程
- Python 使用SMTP發送郵件
- Python 多線程
- Python 2.x與3??.x版本區別
- Python IDE
- Python JSON
- Python3 教程
- Python3 基礎語法
- Python3 基本數據類型
- Python3 解釋器
- Python3 注釋
- Python3 數字運算
- Python3 字符串
- Python3 列表
- Python3 編程第一步
- Python3 條件控制
- Python3 循環
- Python3 函數
- Python3 數據結構
- Python3 模塊
- Python3 輸入和輸出
- Python3 錯誤和異常
- Python3 類
- Python3 標準庫概覽
- 免責聲明