1. 程式人生 > >[Python]第十三章 資料庫支援

[Python]第十三章 資料庫支援

文章目錄

13.1Python資料庫API

所有資料庫的大多數基本功能都相同,因此從理論上說,對於使用其中一種資料庫的程式,很容易對其進行修改以使用另一種資料庫。問題是即便不同模組提供的功能大致相同,它們的介面(API)也是不同的。為解決Python資料庫模組存在的這種問題,人們一致同意開發一個標準資料庫API(DB API)

13.1.1全域性變數

所有與DB API2.0相容的資料庫模組都必須包含三個全域性變數,它們描述了模組的特徵。通過檢查這些變數,看看給定的模組是否是程式能夠接受的。如果不是,就顯示合適的錯誤訊息並退出或者引發異常。
Python DB API的模組屬性

變 量 名 描 述
apilevel 使用的Python DB API版本
threadsafety 模組的執行緒安全程度如何
paramstyle 在SQL查詢中使用哪種引數風格
  • API級別(apilevel):是一個字串常量,指出了使用的API版本。DB API 2.0指出,這個變數的值為’1.0’或’2.0’。
  • 執行緒安全程度(threadsafety):是一個0~3(含)的整數。
    0表示執行緒不能共享模組,而3表示模組是絕對執行緒安全的。1表示執行緒可共享模組本身,但不能共享連線(參見13.1.3節),而2表示執行緒可共享模組和連線,但不能共享遊標。
  • 引數風格(paramstyle):表示當你執行多個類似的資料庫查詢時,如何在SQL查詢中插入引數。

13.1.2異常

異 常 超 類 描 述
tandardError 所有異常的超類
arning StandardError 發生非致命問題時引發
rror StandardError 所有錯誤條件的超類
nterfaceError Error 與介面(而不是資料庫)相關的錯誤
atabaseError Error 與資料庫相關的錯誤的超類
ataError DatabaseError 與資料相關的問題,如值不在合法的範圍內
perationalError DatabaseError 資料庫操作內部的錯誤
ntegrityError DatabaseError 關係完整性遭到破壞,如鍵未通過檢查
nternalError DatabaseError 資料庫內部的錯誤,如遊標無效
rogrammingError DatabaseError 使用者程式設計錯誤,如未找到資料庫表
otSupportedError DatabaseError 請求不支援的功能如回滾

13.1.3連線和遊標

import sqlite3
con=sqlite3.connect('D:\Data\database.db')#連線物件
cur=con.cursor()#遊標物件

要使用底層的資料庫系統,必須先連線到它,為此可使用名稱貼切的函式connect。這個函式接受多個引數具體是哪些取決於要使用的資料庫。
函式connect的常用引數

引數名 描述 是否可選
dsn 資料來源名稱,具體含義隨資料庫而異
user 使用者名稱
password 使用者密碼
host 主機名
database 資料庫名稱

函式connect返回一個連線物件
連線對像的方法

方法名 描述
close() 關閉連線物件。之後,連線物件及其遊標將不可用
commit() 提交未提交的事務——如果支援的話;否則什麼都不做
rollback() 回滾未提交的事務(可能不可用)
cursor() 返回連線的遊標物件

遊標物件的方法

名稱 描述
callproc(name[, params]) 使用指定的引數呼叫指定的資料庫過程(可選)
close() 關閉遊標。關閉後遊標不可用
execute(oper[, params]) 執行一個SQL操作——可能指定引數
executemany(oper, pseq) 執行指定的SQL操作多次,每次都序列中的一組引數
fetchone() 以序列的方式取回查詢結果中的下一行;如果沒有更多的行,就返回None
fetchmany([size]) 取回查詢結果中的多行,其中引數size的值預設為arraysize
fetchall() 以序列的序列的方式取回餘下的所有行
nextset() 跳到下一個結果集,這個方法是可選的
setinputsizes(sizes) 用於為引數預定義記憶體區域
setoutputsize(size[, col]) 為取回大量資料而設定緩衝區長度

遊標物件的屬性

名 稱 描 述
description 由結果列描述組成的序列(只讀)
rowcount 結果包含的行數(只讀)
arraysize fetchmany返回的行數,預設為1

13.1.4型別

對於插入到某些型別的列中的值,底層SQL資料庫可能要求它們滿足一定的條件。為了能夠與底層SQL資料庫正確地互操作,DB API定義了一些建構函式和常量(單例),用於提供特殊的型別和值。
每個模組都必須實現表13-7所示的建構函式和特殊值。有些模組可能沒有完全遵守這一點。

名稱 描述
Date(year, month, day) 建立包含日期值的物件
Time(hour, minute, second) 建立包含時間值的物件
Timestamp(y, mon, d, h, min, s) 建立包含時間戳的物件
DateFromTicks(ticks) 根據從新紀元開始過去的秒數建立包含日期值的物件
TimeFromTicks(ticks) 根據從新紀元開始過去的秒數建立包含時間值的物件
imestampFromTicks(ticks) 根據從新紀元開始過去的秒數建立包含時間戳的物件
Binary(string) 建立包含二進位制字串值的物件
STRING 描述基於字串的列(如CHAR)
BINARY 描述二進位制列(如LONG或RAW)
NUMBER 描述數字列
DATETIME 描述日期/時間列
ROWID 描述行ID列

13.2SQLite和PySQLite

SQLite小型資料庫引擎。它不需要作為獨立的伺服器執行,且可直接使用本地檔案,而不需要集中式資料庫儲存機制。

13.2.1起步

要使用Python標準庫中的SOLite,可通過匯入模組sqlite3來匯入它。

import sqlite3  #匯入模組
conn = sqlite3.connect('somedatabase.db') #建立連線
curs = conn.cursor() #獲取遊標
conn.commit() #提交修改(如果修改了資料)
conn.close() #關閉連線

13.2.2資料庫應用程式演示

目標:將文件轉化成資料庫
在這裡插入圖片描述
寫一個數據轉化檔案

###importdata.py 將資料匯入資料庫
import sqlite3
conn=sqlite3.connect('st.db')#建立連線
curs=conn.cursor()#獲得遊標

#定義一個去除兩邊~的函式
def convert(value):
    if value.startswith('~'):
        return value.strip('~')
    if not value:#如果value是空值,則返回0
        value='0'
    return float(value)
    
#執行遊標——新建表
curs.execute('''
create table stu11(
    id text primary key,
    name text,
    county test,
    age float)
''')
    
query='insert into stu11 values (?,?,?,?)'  #qmark風格使用問號來標記欄位
for line in open('sql.txt'):# 逐行讀取
    fields=line.split('^') #每一行的文字用^分隔成列表
    vals=[convert(f) for f in fields[:4]] #將該列表的每個元素執行convert函式後返回新的列表,取前4個元素([:4]中4不含)
    curs.execute(query,vals)#執行遊標 ——儲存資料
    print(vals)
    
conn.commit()#提交連線,針對改變資料庫的刪除、插入等操作,查詢不需要提交
conn.close()#斷開連線
----------------------------------------------------------------
['07276', 'Jack', 'China', '25']
['07274', 'May', 'Japan', '21']

這樣新建的st.db儲存有stu11這張表,表中有上述兩行資料

寫一個查詢檔案

#query.py
import sqlite3,sys
conn=sqlite3.connect('st.db')#建立連線
curs=conn.cursor()#獲得遊標
query='select * from stu11 where '+sys.argv[1]#sys.argv[1]外部給與的第一個引數
print(query)
curs.execute(query)
names=[f[0] for f in curs.description]#curs.description查看錶結構 f[0]得到域的名字/列名
for row in curs.fetchall():#curs.fetchall()得到執行sql語句後返回的記錄
    for pair in zip(names,row):#zip縫合序列
        print('{}:{}'.format(*pair))
print()

在這裡插入圖片描述

分解:

import sqlite3,sys
conn=sqlite3.connect('st.db')#建立連線
curs=conn.cursor()#獲得遊標
curs.execute('select * from stu11')
curs.description#查看錶結構
---------------------------------------------------------------
(('id', None, None, None, None, None, None),
 ('name', None, None, None, None, None, None),
 ('county', None, None, None, None, None, None),
 ('age', None, None, None, None, None, None))
 -------------------------------------------------------------------
curs.fetchall()#得到執行語句後返回的記錄
[('07276', 'Jack', 'China', 25.0), ('07274', 'May', 'Japan', 21.0)]

#zip縫合函式
a=(('id', None, None, None, None, None, None),
 ('name', None, None, None, None, None, None),
 ('county', None, None, None, None, None, None),
 ('age', None, None, None, None, None, None))
aa=[f[0] for f in a]
b=[('07276', 'Jack', 'China', 25.0), ('07274', 'May', 'Japan', 21.0)]
for bb in b:
	print(list(zip(aa,bb)))
---------------------------------------------------
[('id', '07276'), ('name', 'Jack'), ('county', 'China'), ('age', 25.0)]
[('id', '07274'), ('name', 'May'), ('county', 'Japan'), ('age', 21.0)]

延伸:使用pymysql連線MySQL資料庫
安裝命令:pip install PyMySQL
在這裡插入圖片描述

import pymysql
con=pymysql.connect('localhost','root','123456','execise')#(主機名,使用者名稱,密碼,資料庫名)與本地MYSQL資料庫一致
cur=con.cursor()
q='select * from student;'
cur.execute(q)
cur.fetchall()
#con.close()