1. 程式人生 > >Python-DB接口規範

Python-DB接口規範

date 重要 這樣的 ges 文件 https /usr aer 擁有

threadsafety

線程安全級別。threadsafety 這是一個整數, 取值範圍如下:

  • 0:不支持線程安全, 多個線程不能共享此模塊
  • 1:初級線程安全支持: 線程可以共享模塊, 但不能共享連接
  • 2:中級線程安全支持 線程可以共享模塊和連接, 但不能共享遊標
  • 3:完全線程安全支持 線程可以共享模塊, 連接及遊標.

如果一個資源被共享, 就必需使用自旋鎖或者是信號量這樣的同步原語對其進行原子目標鎖定。對這個目標來說, 磁盤文件和全局變量都不可靠, 並且有可能妨礙。

paramstyle

該模塊支持的 SQL 語句參數風格 。DB-API 支持多種方式的 SQL 參數風格. 這個參數是一個字符串, 表明 SQL 語句中字符串替代的方式。

connect

連接函數。connect 方法生成一個 connect 對象, 我們通過這個對象來訪問數據庫。符合標準的模塊都會實現 connect 方法。connect 函數的參數如下所示:

user            Username  
password        Password  
host            Hostname
database        Database name
dsn             Data source name

數據庫連接參數可以以一個 DSN 字符串的形式提供, 也可以以多個位置相關參數的形式提供(如果你明確知道參數的順序的話), 也可以以關鍵字參數的形式提供。應用示例:

connect(dsn=’myhost:MYDB’,user=’guido’,password=’234$’)

當然,不同的數據庫接口程序可能有些差異,並非都是嚴格按照規範實現,例如MySQLdb則使用 db 參數而不是規範推薦的 database 參數來表示要訪問的數據庫:

  • MySQLdb.connect(host=’dbserv’, db=’inv’, user=’smith’)
  • PgSQL.connect(database=’sales’)
  • psycopg.connect(database=’template1’, user=’pgsql’)
  • gadfly.dbapi20.connect(‘csrDB’, ‘/usr/local/database’)
  • sqlite3.connect(‘marketing/test’)

異常

兼容標準的模塊也應該提供以下這些異常類:

Warning            警告異常基類
Error              錯誤異常基類
InterfaceError     數據庫接口錯誤
DatabaseError      數據庫錯誤
DataError           理數據時出錯
OperationalError    數據庫執行命令時出錯
IntegrityError      數據完整性錯誤
InternalError      數據庫內部出錯
ProgrammingError    SQL 執行失敗
NotSupportedError   試圖執行數據庫不支持的特性  

連接對象

要與數據庫進行通信, 必須先和數據庫建立連接. 連接對象處理命令如何送往服務器, 以及如何從服務器接收數據等基礎功能。 連接成功(或一個連接池)後你就能夠向數據庫服務器發送請求, 得到響應。

方法

連接對象沒有必須定義的數據屬性, 但至少應該以下這些方法:

close()         關閉數據庫連接
commit()        提交當前事務
rollback()      取消當前事務
cursor()        使用這個連接創建並返回一個遊標或類遊標的對象
errorhandler (cxn, cur,  errcls, errval)  

一旦執行了 close() 方法, 再試圖使用連接對象的方法將會導致異常。

對不支持事務的數據庫或者雖然支持事務, 但設置了自動提交(auto-commit)的數據庫系統來說, commit()方法什麽也不做。 如果你確實需要, 可以實現一個自定義方法來關閉自動提交行為。由於 DB-API 要求必須實現此方法, 對那些沒有事務概念的數據庫來說, 這個方法只需要有一條 pass 語句就可以了。

類似 commit(), rollback() 方法僅對支持事務的數據庫有意義。執行完 rollback(), 數據庫將恢復到提交事務前的狀態. 根據 PEP249, 在提交 commit()之前關閉數據庫連接將會自動調用rollback()方法。

對不支持遊標的數據庫來說, cursor()方法仍然會返回一個盡量模仿遊標對象的對象。這些是最低要求。特定數據庫接口程序的開發者可以任意為他們的接口程序添加額外的屬性。

遊標對象

一個遊標允許用戶執行數據庫命令和得到查詢結果。一個 Python DB-API 遊標對象總是扮演遊標的角色, 無論數據庫是否真正支持遊標。也就說,數據庫接口程序必須實現遊標對象。創建遊標對象之後, 你就可以執行查詢或其它命令(或者多個查詢和多個命令), 也可以從結果集中取出一條或多條記錄。

遊標對象擁有的屬性和方法:

arraysize       使用 fechmany()方法一次取出多少條記錄, 默認值為 1
connectionn     創建此遊標對象的連接(可選)
description         返回遊標活動狀態(一個包含七個元素的元組):  (name,  type_code, display_size, internal_ size, precision, scale, null_ok); 只有 name 和 type_code 是必須提供的  
lastrowid       返回最後更新行的 id (可選), 如果數據庫不支持行 id, 默認返回 None)
rowcount        最後一次 execute() 操作返回或影響的行數.  
callproc(func[,args])  調用一個存儲過程
close()             關閉遊標對象
execute(op[,args])    執行一個數據庫查詢或命令
executemany(op,args)  類似 execute() 和 map() 的結合, 為給定的每一個參數準備並執行一個數據庫查詢/命令
fetchone()      得到結果集的下一行
fetchmany([size=cursor.arraysize])      得到結果集的下幾行 (幾 = size)
fetchall()      返回結果集中剩下的所有行
__iter__()      創建一個叠代對象 (可選; 參閱 next())
messages        遊標執行後數據庫返回的信息列表 (元組集合) (可選)
next()      使用叠代對象得到結果集的下一行(可選; 類似 fetchone(), 參閱 __iter__())
nextset()       移到下一個結果集 (如果支持的話)
rownumber       當前結果集中遊標的索引 (以行為單位, 從 0 開始) (可選)
setinput- sizes(sizes) 設置輸入最大值 (必須有, 但具體實現是可選的)
setoutput- size(size[,col]) 設置大列的緩沖區大寫(必須有, 但具體實現是可選的)

遊標對象最重要的屬性是 execute() 和 fetch() 方法. 所有對數據庫服務器的請求都由它們來完成。對fetchmany()方法來說, 設置一個合理的arraysize 屬性會很有用。 當然, 在不需要時,最好關掉遊標對象。如果數據庫支持存儲過程, 則可以使用 callproc() 方法。

類型對象和構造器

通常兩個不同系統的接口要求的參數類型是不一致的, 譬如python調用c函數時Python對象和 C 類型之間就需要數據格式的轉換, 反之亦然。類似的, 在 Python 對象和原生數據庫對象之間也是如此。對於 Python DB-API 的開發者來說, 你傳遞給數據庫的參數是字符串形式的, 但數據庫會根據需要將它轉換為多種不同的形式. 以確保每次查詢能被正確執行。

舉例來說, 一個 Python 字符串可能被轉換為一個 VARCHAR, 或一個TEXT, 或一個BLOB, 或一個原生 BINARY 對象, 或一個 DATE 或 TIME 對象。一個字符串到底會被轉換成什麽類型? 必須小心的盡可能以數據庫期望的數據類型來提供輸入, 因此另一個DB-API的需求是創建一個構造器以生成特殊的對象, 以便能夠方便的將 Python 對象轉換為合適的數據庫對象。以下所列內容描述了可以用於此目的的類。SQL 的 NULL 值被映射為 Pyhton 的 NULL 對象, 也就是 None。

Date(yr,mo,dy)      日期值對象
Time(hr,min,sec)   時間值對象
Timestamp(yr,mo,dy, hr, min,sec)      時間戳對象
DateFromTicks(ticks) 通過自 1970-01-01 00:00:01 utc 以來的 ticks 秒數得到日期
TimeFromTicks(ticks) 通過自 1970-01-01 00:00:01 utc 以來的 ticks 秒數得到時間值對象
TimestampFromTicks(ticks) 通過自 1970-01-01 00:00:01 utc 以來的 ticks 秒數得到時間戳對象
Binary(string)  對應二進制長字符串值的對象
STRING        描述字符串列的對象, 比如 VARCHAR
BINARY        描述二進制長列的對象 比如 RAW, BLOB
NUMBER        描述數字列的對象
DATETIME      描述日期時間列的對象
ROWID          描述 “row ID” 列的對象

DB-API 操作數據庫流程

技術分享

數據庫操作示例

#! /usr/bin/env python
# -*- coding: utf-8 -*-

# *************************************************************
#     Filename @  operatemysql.py
#       Author @  Huoty
#  Create date @  2015-08-16 10:44:34
#  Description @  
# *************************************************************

import MySQLdb

# Script starts from here

# 連接數據庫
db_conn = MySQLdb.connect(host = ‘localhost‘, user= ‘root‘, passwd = ‘123456‘)

# 如果已經創建了數據庫,可以直接用如下方式連接數據庫
#db_conn = MySQLdb.connect(host = "localhost", user = "root",passwd = "123456", db = "testdb")

"""
connect方法常用參數:
    host: 數據庫主機名.默認是用本地主機
    user: 數據庫登陸名.默認是當前用戶
    passwd: 數據庫登陸的秘密.默認為空
    db: 要使用的數據庫名.沒有默認值
    port: MySQL服務使用的TCP端口.默認是3306
    charset: 數據庫編碼
"""

# 獲取操作遊標
cursor = db_conn.cursor()

# 使用 execute 方法執行SQL語句
cursor.execute("SELECT VERSION()")

# 使用 fetchone 方法獲取一條數據庫。
dbversion = cursor.fetchone()

print "Database version : %s " % dbversion

# 創建數據庫
cursor.execute("create database if not exists dbtest")

# 選擇要操作的數據庫
db_conn.select_db(‘dbtest‘);

# 創建數據表SQL語句
sql = """CREATE TABLE if not exists employee(
         first_name CHAR(20) NOT NULL,
         last_name CHAR(20),
         age INT,  
         sex CHAR(1),
         income FLOAT )"""

try:
    cursor.execute(sql)
except Exception, e:
    # Exception 是所有異常的基類,這裏表示捕獲所有的異常
    print "Error to create table:", e

# 插入數據
sql = """INSERT INTO employee(first_name,
         last_name, age, sex, income)
         VALUES (‘%s‘, ‘%s‘, %d, ‘%s‘, %d)"""

# Sex: Male男, Female女

employees = (
        {"first_name": "Mac", "last_name": "Mohan", "age": 20, "sex": "M", "income": 2000},
        {"first_name": "Wei", "last_name": "Zhu", "age": 24, "sex": "M", "income": 7500},
        {"first_name": "Huoty", "last_name": "Kong", "age": 24, "sex": "M", "income": 8000},
        {"first_name": "Esenich", "last_name": "Lu", "age": 22, "sex": "F", "income": 3500},
        {"first_name": "Xmin", "last_name": "Yun", "age": 31, "sex": "F", "income": 9500},
        {"first_name": "Yxia", "last_name": "Fun", "age": 23, "sex": "M", "income": 3500}
        )

try:
    # 清空表中數據
    cursor.execute("delete from employee")
    # 執行 sql 插入語句
    for employee in employees:
        cursor.execute(sql % (employee["first_name"],             employee["last_name"],             employee["age"],             employee["sex"],             employee["income"]))
    # 提交到數據庫執行
    db_conn.commit()
    # 對於支持事務的數據庫, 在Python數據庫編程中,
    # 當遊標建立之時,就自動開始了一個隱形的數據庫事務。
    # 用 commit 方法能夠提交事物
except Exception, e:
    # Rollback in case there is any error
    print "Error to insert data:", e
    #b_conn.rollback()

print "Insert rowcount:", cursor.rowcount
# rowcount 是一個只讀屬性,並返回執行execute(方法後影響的行數。)

# 數據庫查詢操作:
#    fetchone()      得到結果集的下一行
#    fetchmany([size=cursor.arraysize])  得到結果集的下幾行
#    fetchall()      返回結果集中剩下的所有行
try:
    # 執行 SQL
    cursor.execute("select * from employee")

    # 獲取一行記錄
    rs = cursor.fetchone()
    print rs

    # 獲取余下記錄中的 2 行記錄
    rs = cursor.fetchmany(2)
    print rs

    # 獲取剩下的所有記錄
    ars =  cursor.fetchall()
    for rs in ars:
        print rs
    # 可以用 fetchall 獲得所有記錄,然後再遍歷
except Exception, e:
    print "Error to select:", e

# 數據庫更新操作
sql = "UPDATE employee SET age = age + 1 WHERE sex = ‘%c‘" % (‘M‘)
try:
    # 執行SQL語句
    cursor.execute(sql)
    # 提交到數據庫執行
    db_conn.commit()
    cursor.execute("select * from employee")
    ars =  cursor.fetchall()
    print "After update: ------"
    for rs in ars:
        print rs
except Exception, e:
    # 發生錯誤時回滾
    print "Error to update:", e
    db.rollback()

# 關閉數據庫連接
db_conn.close()

參考資料

https://www.python.org/dev/peps/pep-0249/
https://wiki.python.org/moin/DatabaseProgramming
https://wiki.python.org/moin/DbApi3

Python-DB接口規範