Python 標準數(shù)據(jù)庫接口為 Python DB-API,Python DB-API為開發(fā)人員提供了數(shù)據(jù)庫應用編程接口。
Python 數(shù)據(jù)庫接口支持非常多的數(shù)據(jù)庫,你可以選擇適合你項目的數(shù)據(jù)庫:
DB-API 是一個規(guī)范. 它定義了一系列必須的對象和數(shù)據(jù)庫存取方式, 以便為各種各樣的底層數(shù)據(jù)庫系統(tǒng)和多種多樣的數(shù)據(jù)庫接口程序提供一致的訪問接口 。
Python的DB-API,為大多數(shù)的數(shù)據(jù)庫實現(xiàn)了接口,使用它連接各數(shù)據(jù)庫后,就可以用相同的方式操作各數(shù)據(jù)庫。
Python DB-API使用流程:
如果執(zhí)行后的輸出結果如下所示,意味著你沒有安裝 MySQLdb 模塊:#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
Traceback (most recent call last):
File "test.py", line 3, in <module>
import MySQLdb
ImportError: No module named MySQLdb
Python使用MySQL的流程:
執(zhí)行以上腳本輸出結果如下:#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# 使用execute方法執(zhí)行SQL語句
cursor.execute("SELECT VERSION()")
# 使用 fetchone() 方法獲取一條數(shù)據(jù)
data = cursor.fetchone()
print "Database version : %s " % data
# 關閉數(shù)據(jù)庫連接
db.close()
Database version : 5.0.45
數(shù)據(jù)庫插入操作#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# 如果數(shù)據(jù)表已經存在使用 execute() 方法刪除表。
cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
# 創(chuàng)建數(shù)據(jù)表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)
# 關閉數(shù)據(jù)庫連接
db.close()
以上例子也可以寫成如下形式:#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
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:
# 執(zhí)行sql語句
cursor.execute(sql)
# 提交到數(shù)據(jù)庫執(zhí)行
db.commit()
except:
# Rollback in case there is any error
db.rollback()
# 關閉數(shù)據(jù)庫連接
db.close()
實例:#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
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:
# 執(zhí)行sql語句
cursor.execute(sql)
# 提交到數(shù)據(jù)庫執(zhí)行
db.commit()
except:
# 發(fā)生錯誤時回滾
db.rollback()
# 關閉數(shù)據(jù)庫連接
db.close()
以上腳本執(zhí)行結果如下:#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 查詢語句
sql = "SELECT * FROM EMPLOYEE \
WHERE INCOME > '%d'" % (1000)
try:
# 執(zhí)行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"
# 關閉數(shù)據(jù)庫連接
db.close()
fname=Mac, lname=Mohan, age=20, sex=M, income=2000
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 更新語句
sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = '%c'" % ('M')
try:
# 執(zhí)行SQL語句
cursor.execute(sql)
# 提交到數(shù)據(jù)庫執(zhí)行
db.commit()
except:
# 發(fā)生錯誤時回滾
db.rollback()
# 關閉數(shù)據(jù)庫連接
db.close()
執(zhí)行事務#!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
# 打開數(shù)據(jù)庫連接
db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操作游標
cursor = db.cursor()
# SQL 刪除語句
sql = "DELETE FROM EMPLOYEE WHERE AGE > '%d'" % (20)
try:
# 執(zhí)行SQL語句
cursor.execute(sql)
# 提交修改
db.commit()
except:
# 發(fā)生錯誤時回滾
db.rollback()
# 關閉連接
db.close()
對于支持事務的數(shù)據(jù)庫, 在Python數(shù)據(jù)庫編程中,當游標建立之時,就自動開始了一個隱形的數(shù)據(jù)庫事務。# SQL刪除記錄語句
sql = "DELETE FROM EMPLOYEE WHERE AGE > '%d'" % (20)
try:
# 執(zhí)行SQL語句
cursor.execute(sql)
# 向數(shù)據(jù)庫提交
db.commit()
except:
# 發(fā)生錯誤時回滾
db.rollback()
DB API中定義了一些數(shù)據(jù)庫操作的錯誤及異常,下表列出了這些錯誤和異常:
異常 | 描述 |
---|---|
Warning | 當有嚴重警告時觸發(fā),例如插入數(shù)據(jù)是被截斷等等。必須是 StandardError 的子類。 |
Error | 警告以外所有其他錯誤類。必須是 StandardError 的子類。 |
InterfaceError | 當有數(shù)據(jù)庫接口模塊本身的錯誤(而不是數(shù)據(jù)庫的錯誤)發(fā)生時觸發(fā)。 必須是Error的子類。 |
DatabaseError | 和數(shù)據(jù)庫有關的錯誤發(fā)生時觸發(fā)。 必須是Error的子類。 |
DataError | 當有數(shù)據(jù)處理時的錯誤發(fā)生時觸發(fā),例如:除零錯誤,數(shù)據(jù)超范圍等等。 必須是DatabaseError的子類。 |
OperationalError | 指非用戶控制的,而是操作數(shù)據(jù)庫時發(fā)生的錯誤。例如:連接意外斷開、 數(shù)據(jù)庫名未找到、事務處理失敗、內存分配錯誤等等操作數(shù)據(jù)庫是發(fā)生的錯誤。 必須是DatabaseError的子類。 |
IntegrityError | 完整性相關的錯誤,例如外鍵檢查失敗等。必須是DatabaseError子類。 |
InternalError | 數(shù)據(jù)庫的內部錯誤,例如游標(cursor)失效了、事務同步失敗等等。 必須是DatabaseError子類。 |
ProgrammingError | 程序錯誤,例如數(shù)據(jù)表(table)沒找到或已存在、SQL語句語法錯誤、 參數(shù)數(shù)量錯誤等等。必須是DatabaseError的子類。 |
NotSupportedError | 不支持錯誤,指使用了數(shù)據(jù)庫不支持的函數(shù)或API等。例如在連接對象上 使用.rollback()函數(shù),然而數(shù)據(jù)庫并不支持事務或者事務已關閉。 必須是DatabaseError的子類。 |
建立數(shù)據(jù)庫,進行一些簡單操作
1.簡單的創(chuàng)建一個’user‘表,并且插入一些數(shù)據(jù)。user表中只有兩個字段:userid和username。代碼如下:
import MySQLdb conn=MySQLdb.connect(host='127.0.0.1',port=3306,user='root',passwd='199331',db='test',charset='utf8') cur=conn.cursor() cur.execute(""" create table if not EXISTS user ( userid int(11) PRIMARY KEY , username VARCHAR(20) ) """) for i in range(1,10): cur.execute("insert into user(userid,username) values('%d','%s')" %(int(i),'name'+str(i))) conn.commit() cur.close() conn.close()
我們用Navicat打開數(shù)據(jù)庫,查看一下結果,,可以看到成功創(chuàng)建表,并且插入了十個數(shù)據(jù)。
2.我們操作一下Cursor里面的一些方法。
execute()方法:執(zhí)行SQL,將一個結果從數(shù)據(jù)庫獲取到客戶端
fetch*()方法:移動rownumber,返回數(shù)據(jù)。
例如我們有如下代碼:
sql='select * from user'
cursor.execute(sql)
print(cursor.rowcount)
rs=cursor.fetchone()
print(rs)
rs=cursor.fetchmany(3)
print(rs)
rs=cursor.fetchall()print(rs)
結果如下:
我們可以看出執(zhí)行查詢全部數(shù)據(jù)后,rowcount為10
執(zhí)行fetchone()方法后返回一個數(shù)據(jù),執(zhí)行fetchmany(3)后返回3條數(shù)據(jù),執(zhí)行fetchall()后返回剩下的所有數(shù)據(jù)。
再有如下代碼:
res=cursor.fetchall()
for row in res:
print('userid=%s,userna=%s' %row)
此時的執(zhí)行結果為:
3.上面介紹的便是數(shù)據(jù)庫中常說的Select操作,下面我們介紹數(shù)據(jù)的更新,即:insert、update、delete操作。值得注意的是在這部分操作時需要注意的是是否數(shù)據(jù)發(fā)生異常,如果數(shù)據(jù)沒有發(fā)生異常,我們便可以直接使用commit()進行提交(注:如沒有使用commit,則數(shù)據(jù)庫不會發(fā)生任何變化)。但是如果出現(xiàn)了異常,那么久需要使用rollback()進行回滾。
3.1先來看一個沒有異常,正常提交的例子:
sql_insert='insert into user(userid,username) values(10,"name10")'
sql_update='update user set username="name91" where userid=9'
sql_delete='delete from user where userid=3'
cursor.execute(sql_insert)
print(cursor.rowcount)
cursor.execute(sql_update)
print(cursor.rowcount)
cursor.execute(sql_delete)
print(cursor.rowcount)
conn.commit()
上面的操作即是:添加一條(10,’name10‘)的數(shù)據(jù)、將userid=9的username修改為’name91‘,刪除userid=3的數(shù)據(jù),執(zhí)行上面代碼后我們來用Navicat查看一下數(shù)據(jù):
從結果可以看到代碼執(zhí)行正常。
3.2.再來看一個有異常的數(shù)據(jù)
sql_insert='insert into user(userid,username) values(10,"name10")'
sql_update='update user set username="name91" where userid=9'
# sql_delete='delete from user where userid=3'
# ##error
sql_delete='delete from user where useri=3'
try:
cursor.execute(sql_insert)
print(cursor.rowcount)
cursor.execute(sql_update)
print(cursor.rowcount)
cursor.execute(sql_delete)
print(cursor.rowcount)
except Exception as e:
print(e)
conn.rollback()
這里的insert和update操作一樣,只不過把delete里面的userid字段錯誤的寫成了useri,執(zhí)行代碼:
可以看到顯示出異常,這時我們來看一下數(shù)據(jù)庫數(shù)據(jù):
數(shù)據(jù)沒有任何改變。這就是rollback()的作用
因此,我們以后再寫增刪改查操作時,最好把操作放入一個try控制塊中,來避免一些不必要的錯誤。
下面是一個銀行轉賬的實例:
#-*-encoding:utf-8 -*-
import MySQLdb
conn=MySQLdb.connect(host='127.0.0.1',port=3306,user='root',passwd='199331',db='test',charset='utf8')
cur=conn.cursor()
##創(chuàng)建數(shù)據(jù)表
cur.execute("""
create table if not EXISTS account(
accid int(10) PRIMARY KEY ,
money int(10)
)
""")
###插入兩行數(shù)據(jù)
cur.execute('insert into account(accid,money) VALUES (1,110)')
cur.execute('insert into account(accid,money) VALUES (2,10)')
conn.commit()
cur.close()
conn.close()
#-*- encoding:utf-8 -*-
import sys
import MySQLdb
class TransferMoney(object):
def __init__(self,conn):
self.conn=conn
def check_acct_available(self,accid):
cursor=self.conn.cursor()
try:
sql='select * from account where accid=%s' %accid
cursor.execute(sql)
print('check_acct_available'+sql)
rs=cursor.fetchall()
if len(rs)!=1:
raise Exception('賬號%s 不存在' %accid)
finally:
cursor.close()
def has_enough_money(self,accid,money):
cursor=self.conn.cursor()
try:
sql='select * from account where accid=%s and money>%s' %(accid,money)
cursor.execute(sql)
print('check_money_available'+sql)
rs=cursor.fetchall()
if len(rs)!=1:
raise Exception('賬號%s 沒有足夠錢' %accid)
finally:
cursor.close()
def reduce_money(self,accid,money):
cursor=self.conn.cursor()
try:
sql='update account set money=money-%s where accid=%s' %(money,accid)
cursor.execute(sql)
print('reduce money'+sql)
rs=cursor.fetchall()
if cursor.rowcount!=1:
raise Exception('賬號%s 減款失敗' %accid)
finally:
cursor.close()
def add_money(self,accid,money):
cursor=self.conn.cursor()
try:
sql='update account set money=money+%s where accid=%s' %(money,accid)
cursor.execute(sql)
print('reduce money'+sql)
rs=cursor.fetchall()
if cursor.rowcount!=1:
raise Exception('賬號%s 加款失敗' %accid)
finally:
cursor.close()
def transfer(self,source_accid,target_accid,money):
###檢測兩個賬號是否可用
try:
self.check_acct_available(source_accid)
self.check_acct_available(target_accid)
####檢測付款人是否有足夠的錢
self.has_enough_money(source_accid,money)
self.reduce_money(source_accid,money)
self.add_money(target_accid,money)
self.conn.commit()
except Exception as e:
self.conn.rollback()
raise e
if __name__=='__main__':
source_accid=sys.argv[1]
target_accid=sys.argv[2]
money=sys.argv[3]
conn=MySQLdb.connect(host='127.0.0.1',port=3306,user='root',passwd='199331',db='test',charset='utf8')
tr_money=TransferMoney(conn)
try:
tr_money.transfer(source_accid,target_accid,money)
except Exception as e:
print('出現(xiàn)問題'+str(e))
finally:
conn.close()
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網友會為你解答??! 點擊進入論壇