GitHub@orca-j35,全部筆記均託管於 python_notes 倉庫
歡迎任何形式的轉載,但請務必註明出處。html參考:python
PEP 249 是 Python 數據庫 API 規範的 2.0 版本,PEP 248 是 1.0 版本。PEP 249 不只包含 Python 數據庫 API 規範,還描述了一組具有通用性的可選擴展。早先的 1.0 版本(PEP 248)依然具有參考價值,但鼓勵模塊編寫者在開發新接口時以 PEP 249 爲參考。PEP 249 的目標是讓"數據庫訪問模塊"提供類似的接口,實現一致性,從而讓代碼便於移植。mysql
若是須要了解與數據庫接口相關的各類庫,請看 Database Topic Guide。git
本規範約定,需經過 Connection 對象來訪問數據庫,所以"數據庫訪問模塊"必須提供用來建立 Connection 對象的構造器。程序員
🪓connect( parameters... )github
該構造器用於建立數據庫鏈接,返回值是 Connection 對象。算法
parameters... 表示與數據庫相關的參數。sql
註釋:數據庫
構造器 connect( parameters... ) 的參數應以關鍵字參數的形式實現,並按照下表中的前後順序排列:後端
Parameter Meaning dsn
Data source name as string user
User name as string (optional) password
Password as string (optional) host
Hostname (optional) database
Database name (optional) E.g. a connect could look like this:
connect(dsn='myhost:MYDB', user='guido', password='234$')
數據庫訪問模塊必須定義本節中給出的各類全局變量
🔧apilevel
一個字符串常量,表示模塊支持的 DB API 版本。
目前只容許使用字符串 "1.0" (對應 PEP 248) 和 "2.0" (對應 PEP 249)。若是未給出該常量,則假設模塊使用 DB-API 1.0。
🔧threadsafety
一個整數常量,用於說明模塊接口支持的線程安全級別,可選值以下:
threadsafety | Meaning |
---|---|
0 | Threads may not share the module. |
1 | Threads may share the module, but not connections. |
2 | Threads may share the module and connections. |
3 | Threads may share the module, connections and cursors. |
share 意味着兩個線程在使用同一個資源時,無需使用互斥信號(mutex semaphore)來實現資源鎖。注意,即便已使用互鎖機制(mutex)來管理訪問權限,也沒法始終確保外部資源的線程安全: 由於外部資源可能會依賴於全局變量,或依賴於你沒法控制的其它外部資源。
一個字符串常量,用於說明模塊接口指望的參數標記(parameter marker)的格式化風格,可選值以下:
paramstyle | Meaning |
---|---|
qmark |
Question mark style, e.g. ...WHERE name=? |
numeric |
Numeric, positional style, e.g. ...WHERE name=:1 |
named |
Named style, e.g. ...WHERE name=:name |
format |
ANSI C printf format codes, e.g. ...WHERE name=%s |
pyformat |
Python extended format codes, e.g. ...WHERE name=%(name)s |
模塊實現者應優先考慮使用 numeric
, named
或 pyformat
,由於它們清晰度和靈活性更佳。
import sqlite3 print(sqlite3.paramstyle) #> qmark import pymysql print(pymysql.paramstyle) #> pyformat import mysql.connector print(mysql.connector.paramstyle) #> pyformat
可見,sqlite3
使用 ?
做爲參數標記,所以可以使用如下語句插入數據:
cursor.execute("INSERT INTO user (id,name) VALUES (?, ?)", (6, 'liuyi'))
數據庫訪問模塊應經過下述 Exception 類(或其子類)來提供所有錯誤信息:
☣Warning
必須繼承自 Python StandardError
,遇到下述相似狀況時,應拋出該異常:
Error
必須繼承自 Python StandardError
,模塊中其它全部 error 異常都應是 Error
的子類。你能夠在單個 except
語句中使用 Error
來捕捉全部 error 異常。Warning
不該被視爲 error,所以不是 Error
的子類。
InterfaceError
必須是 Error
的子類表示那些與數據庫接口有關,而與數據庫自己無關的錯誤。
DatabaseError
必須是 Error
的子類,表示那些與數據庫有關的錯誤。
DataError
必須是 DatabaseError
的子類,表示因處理數據而致使的錯誤,例如: 除數是 0;或數值超出範圍
OperationalError
必須是 DatabaseError
的子類,表示與數據庫操做相關的錯誤,而且不必定是在程序員的控制之下形成的錯誤。好比,意外狀況致使斷開鏈接;找不到數據源名稱;沒法處理事務,處理期間發生內存分配錯誤等
IntergrityError
必須是 DatabaseError
的子類,表示數據操做違反了數據庫的完整性約束。好比,外鍵檢查失敗。
InternalError
必須是 DatabaseError
的子類,遇到數據庫內部錯誤時會拋出該異常。好比,遊標(cursor)再也不有效,或事務不一樣步等。
ProgrammingError
必須是 DatabaseError
的子類,表示程序邏輯出錯。好比,未找到表或表已經存在;SQL 語句中的語法錯誤;指定了錯誤的參數數量等。
NotSupportedError
必須是 DatabaseError
的子類,當使用了數據庫不支持的 API 或方法時會拋出該異常。好比,在不支持 SQL 事務(或已關閉事務)的 connection 上請求 .rollback()
方法。
下面是 Exception 類的繼承結構:
StandardError |__Warning |__Error |__InterfaceError |__DatabaseError |__DataError |__OperationalError |__IntegrityError |__InternalError |__ProgrammingError |__NotSupportedError
⚠The values of these exceptions are not defined. They should give the user a fairly good idea of what went wrong, though.
Connection 對象必須實現本節中給出的各類方法。
當即關閉鏈接(而不是每次都調用 .__del__()
方法)
在 Connection 對象上調用 .close()
後,"鏈接"將再也不可用。若是試圖對此"鏈接"作任何操做都會拋出 Error
(或其子類)異常。這一樣適用於試圖使用此"鏈接"的全部遊標(cursor)對象。
⚠若是沒有 commit 變動就關閉了"鏈接",將隱式執行 rollback 操做。
將任何掛起的事務(transaction)提交到數據庫。
⚠若是數據庫支持自動提交(auto-commit)功能,必須先關閉自動提交功能。還能夠提供一個接口方法來從新開啓自動提交功能。
若是數據庫模塊不支持事務,則應使用一個空方法(void functionality)來實現 .commit()
這是一個可選方法,由於並不是全部數據庫都支持事務。
若是數據庫確實支持事務,.rollback()
方法會使數據庫回滾到任何掛起事務的以前。若是沒有 commit 變動就關閉了"鏈接",將隱式執行 rollback 操做。
註釋:If the database does not support the functionality required by the method, the interface should throw an exception in case the method is used.
The preferred approach is to not implement the method and thus have Python generate an
AttributeError
in case the method is requested. This allows the programmer to check for database capabilities using the standardhasattr()
function.For some dynamically configured interfaces it may not be appropriate to require dynamically making the method available. These interfaces should then raise a
NotSupportedError
to indicate the non-ability to perform the roll back when the method is invoked.
使用 Connection 對象返回一個新的 Cursor 對象。
若是數據庫並無直接提供遊標的概念,則模塊必須使用其餘方式來模擬規範所需的「遊標」。
數據庫接口能夠選擇是否爲.cursor()
提供一個字符串參數來構建具名 cursor。該功能並不屬於規範中的一部分,由於它會使.fetch*()
方法的語義複雜化。
Cursor 對象表示數據庫的遊標(cursor),用於管理 fetch 操做的上下文(context)。由同一個 connection 建立的 cursor 之間並非孤立的(isolated),某個 cursor 對數據庫進行的任何改動都會被其它 cursor 當即看到。由不一樣 connection 建立的 cursor 之間多是相互孤立的,也可能不是相互孤立的,這取決於事務支持的實現方式。(還能夠看看 connection 的 rollback()
和 .commit()
方法)
Cursor 對象必須實現本節中給出的各類方法和屬性。
該只讀屬性自己是一個序列,序列中的每一個元素又對應爲一個子序列,子序列由如下 7 個條目組成。子序列中存放着對結果列(column)的描述信息,每一個子序列對應一個結果列。
name
type_code
- 此列在數據庫中的類型display_size
internal_size
precision
scale
null_ok
前兩個條目(name
和 type_coe
)是必填項,後面五個是選填項。若是不能提供有意義的值,則設置爲 None
。
在遇到如下兩種狀況時,.description
的值是 None
:
.execute*()
方法執行操做若是須要了解 type_code
的含義,請參考 Type Objects 小節
該只讀屬性用於存放如下兩種狀況涉及到的行數:
.execute*()
調用所得結果的行數( 針對 SELECT 等 DQL 語句).execute*()
調用所影響的行數( 針對 UPDATE 或 INSERT 等 DML 語句)註釋:The term number of affected rows generally refers to the number of rows deleted, updated or inserted by the last statement run on the database cursor. Most databases will return the total number of rows that were found by the corresponding
WHERE
clause of the statement. Some databases use a different interpretation forUPDATE
s and only return the number of rows that were changed by theUPDATE
, even though theWHERE
clause of the statement may have found more matching rows. Database module authors should try to implement the more common interpretation of returning the total number of rows found by theWHERE
clause, or clearly document a different interpretation of the.rowcount
attribute.
在遇到如下兩種狀況時,.rowcount
的值爲 -1
:
.execute*()
方法在從此的 DB API 規範中會從新定義此種狀況,將返回值由 -1
改成 None
Therowcount
attribute may be coded in a way that updates its value dynamically. This can be useful for databases that return usablerowcount
values only after the first call to a .fetch*() method.
該可讀/寫屬性表示每次調用 fetchmany()
時可獲取到的結果集中的行數。該字段的默認值是 1
,意味着每次調用 fetchmany()
函數會獲取結果集中的一行數據。
在實現 .fetchmany()
時必須遵照 .arraysize
字段,但在實現過程當中也能夠一次一行的和數據庫交互。在實現 executemany()
方法時,也可以使用 .arrarsize
字段。
🔨.callproc( procname [, parameters ] )
(此方法是可選實現,由於並不是全部數據庫都支持"存儲過程(stored procedures)")
註釋:If the database does not support the functionality required by the method, the interface should throw an exception in case the method is used.
The preferred approach is to not implement the method and thus have Python generate an
AttributeError
in case the method is requested. This allows the programmer to check for database capabilities using the standardhasattr()
function.For some dynamically configured interfaces it may not be appropriate to require dynamically making the method available. These interfaces should then raise a
NotSupportedError
to indicate the non-ability to perform the roll back when the method is invoked.
❓Q: 什麼是"存儲過程"?
A: 可參考《SQL 必知必會》->第19課 使用存儲過程,簡單來講存儲過程就好像是自定義函數。
.callproc()
的功能是調用名爲 procname 的"存儲過程",參數序列 parameters 中包含的條目即是"存儲過程"所需的參數。調用結果將被表示爲輸入序列的副本,並在返回前對參數進行修改:
IN
)參數保持不變OUT
)參數和輸入/輸出(INOUT
)參數將被替換爲可能的新值"存儲過程"也能夠提供一個做爲輸出的結果集。此時必須經過標準的 .fetch*()
方法來獲取。
📝某些庫的實現方式可能並不兼容本條約定,好比 pymysql
:
"""Defining the Stored Routine in MySQL: CREATE PROCEDURE multiply(IN pFac1 INT, IN pFac2 INT, OUT pProd INT) BEGIN SET pProd := pFac1 * pFac2; END """ import pymysql try: conn = pymysql.connect( host="localhost", port=3306, user='root', password='orca_j35', database='test', ) cursor = conn.cursor() args = (5, 5, 0) # callproc()直接返回輸入序列,不兼容本條約定 print(cursor.callproc('multiply', args)) #> (5, 5, 0) print(cursor.execute('SELECT @_multiply_2')) #> 1 print(cursor.fetchall()) #> ((25,),) except Exception as ex: print(ex)
🔨.close()
當即關閉 cursor (而不是每次都調用 .__del__()
方法)
在 cursor 對象上調用 .close()
後,cursor 將不在可用。若是以後試圖使用這個 cursor 執行任何操做,都會引起一個 Error
或其(子類)的異常。
🔨.execute(operation [, parameters])
準備並執行一個數據庫操做: query 或 command
parameters 能夠是序列或映射,parameters 中的元素將被綁定到操做 operation 內含的變量中。需以數據庫特定的標識符來表示變量(詳見 paramstyle
屬性)
註釋:The module will use the
__getitem__
method of the parameters object to map either positions (integers) or names (strings) to parameter values. This allows for both sequences and mappings to be used as input.The term bound refers to the process of binding an input value to a database execution buffer. In practical terms, this means that the input value is directly used as a value in the operation. The client should not be required to "escape" the value so that it can be used — the value should be equal to the actual database value.
cursor 將保留(retain)對 operation 的引用。若是再次傳入相同的 operation 對象,那麼 cursor 能夠優化這種行爲。這對於那種(屢次)使用相同的 operation,但會將不一樣 parameters 綁定到該 operation 的狀況最有效。
爲了在重用 operation 時得到最大的效率,最好使用 .setinputsizes()
方法提早指定 parameters 中各參數的類型和大小。參數與預約義信息不匹配也屬於合法行爲,但在實現上應考慮對可能會出現的效率損失進行補償(compensate)。
parameters 也能夠是元組列表(list of tuples),例如,在單個操做中插入多行。可是不推薦這種作法: 應使用 .executemany()
方法。
此方法未定義返回值。
示例 -
import pymysql print(pymysql.paramstyle) #> pyformat conn = pymysql.connect( host="localhost", port=3306, user='root', password='orca_j35', database='test', ) cursor = conn.cursor() cursor.execute("INSERT INTO user(name) VALUES (%s)", ('小劉', )) cursor.execute('SELECT name,id FROM user Where name=%s', ('小劉', )) print(cursor.fetchall()) #> (('小劉', 15),)
🔨.executemany( operation, seq_of_parameters )
準備一個數據庫操做(query 或 command),而後逐一使用 seq_of_parameters 中包含的序列或映射來執行該數據庫操做。也就是說,.executemany()
方法能夠在一次調用中處理 seq_of_parameters 中的全部序列。
數據庫模塊有兩種實現 .executemany()
的方式:
.execute()
方法若是 .executemany()
執行了會生成一個或多個結果集(result sets)的 operation,便會構成未定義行爲;當檢測到經過調用操做建立告終果集時,容許(非必須)實現拋出一個異常。
適用於 .execute()
的註釋也適用於此方法。
此方法未定義返回值。
🔨.fetchone()
獲取"查詢結果集(query result set)"中的下一行,並將其表示爲單個序列。若是沒有更多可用數據則會返回 None
。
註釋:數據庫接口可能會使用數組和其餘優化方式來實現數據行的獲取。所以在調用
fetchone()
時,並不能保證相應的 cursor 只會向前移動一行,可能會移動多行。
若是先前調用的 .execute*()
方法並未產生任何結果集,或者還沒有調用 .execute*()
,則應拋出 Error
(或其子類)異常。
🔨.fetchmany([size=cursor.arraysize])
向後獲取查詢結果集中的多個行,並返回一個包含各行數據的序列(e.g. a list of tuples),每一行數據會被表示爲一個子序列。當結果集中沒有更多可用行時,則會返回一個空序列。
每次調用所獲取的行數由 size 參數決定。若是沒有傳入 size 參數,則由 cursor 的 arraysize
屬性來肯定要獲取的行數。該方法應盡力嘗試獲取 size 行數據,若是結果集中的可用行數小於 size,則返回的函數可能少於 size。
若是先前調用的 .execute*()
方法並未產生任何結果集,或者還沒有調用 .execute*()
,則應拋出 Error
(或其子類)異常。
⚠: size 參數的大小會影響性能。爲了得到最佳性能,一般最好將 cursor 的 arraysize
屬性用做 size 的值。若是使用自定義 size 值,那麼最好在每次調用 .fetchmany()
時都使用相同的 size 值。
🔨.fetchall()
獲取查詢結果集中全部(剩餘)的行,並返回一個包含各行數據的序列(e.g. a list of tuples),每一行數據會被表示爲一個子序列。
⚠cursor 的 arraysize
屬性可能會影響此操做的性能。
若是先前調用的 .execute*()
方法並未產生任何結果集,或者還沒有調用 .execute*()
,則應拋出 Error
(或其子類)異常。
🔨.nextset()
(此方法是可選實現,由於並不是全部數據庫都支持"多結果集(multiple result sets)")
註釋:If the database does not support the functionality required by the method, the interface should throw an exception in case the method is used.
The preferred approach is to not implement the method and thus have Python generate an
AttributeError
in case the method is requested. This allows the programmer to check for database capabilities using the standardhasattr()
function.For some dynamically configured interfaces it may not be appropriate to require dynamically making the method available. These interfaces should then raise a
NotSupportedError
to indicate the non-ability to perform the roll back when the method is invoked.
此方法會使 cursor 跳至下一個可用的結果集,並丟棄當前結果集中剩餘的全部行。
若是不存在更多的結果集,該方法將返回 None
;不然,該方法會返回一個真值,在這以後調用的 .fetch()
方法將返回下一個結果集中的行。
若是先前調用的 .execute*()
方法並未產生任何結果集,或者還沒有調用 .execute*()
,則應拋出 Error
(或其子類)異常。
"""在MySQL中定義一個返回多結果集的存儲過程: CREATE DEFINER=`root`@`localhost` PROCEDURE `multi_select`() BEGIN SELECT name FROM `user`; SELECT id FROM `user`; END """ """user表中的數據以下: name | id "小明" | "1" "小紅" | "2" "小剛" | "3" "小燦" | "4" """ import pymysql conn = pymysql.connect( host="localhost", port=3306, user='root', password='orca_j35', database='test', ) cursor = conn.cursor() cursor.callproc('multi_select') print(cursor.fetchone()) if cursor.nextset(): print(cursor.fetchall())
輸出:
('小明',) ((1,), (2,), (3,), (4,))
🔨.setinputsizes(sizes)
.execute( operation [, parameters]).executemany( operation, seq_of_parameters )
在調用 .execute*()
以前,可以使用該方法預約義 .execute*()
的"操做參數"(parameters 或 seq_of_parameters)的內存區域。
sizes 參數應是一個序列,該序列中的項應和"輸入參數"中的項相互對應,而且是相同的 Type Object
或者是表示字符串參數的最大長度的整數。若是某一項的值是 None
,則不會爲該列保留預約義的內存區域——這樣能夠避免爲大尺寸的"輸入參數"預留過大的內存區域。
應在使用 .execte*()
以前調用 .setinputsizes()
。
數據庫模塊的實現者能夠自由選擇是否實現此方法,而且模塊的使用者也能夠自由選擇是否使用此方法。
🔨.setoutputsize(size [, column])
爲獲取"大數據列"(e.g. LONG
s, BLOB
s, etc.)而設置的列緩衝區。column 參數用於指定目標列在結果序列中的索引位置。若是不設置 column,則默認爲 cursor 中的所有大數據列設置尺寸爲 size 的緩衝區。
應在使用 .execte*()
以前調用 .setoutputsize()
。
數據庫模塊的實現者能夠自由選擇是否實現此方法,而且模塊的使用者也能夠自由選擇是否使用此方法。
許多數據庫都須要具有特定格式的輸入,以便經過 SQL 操做將輸入參數綁定到數據庫中。例如,假如要向數據庫的 DATE
列輸入數據,就必須以"特定的字符串格式"將輸入數據綁定到數據庫中。"Row ID" 列或 large binary 項(e.g. blobs or RAW
columns)也存在相似的問題。這點對於 Python 來講並不友好,由於傳遞給 execute*()
的參數是無類型的。當數據庫模塊看到 Python 字符串對象時,它並不知道應該將其綁定到何種數據庫類型 —— 數據庫模塊會很困惑,是該綁定到 CHAR
列,仍是綁定到 BINARY
項,抑或是綁定到 DATE
喃?
爲了解決上述問題,模塊必須提供如下構造器,從而能夠建立可以保持特定值的對象。當咱們將下述對象傳遞給 cursor 的方法時,模塊就可以檢查到輸入參數的正確類型,並將其綁定到數據庫中。
模塊將包含如下的構造函數:
此函數會構造一個保存 data 值的對象。
此函數會構造一個保存 time 值的對象。
此函數會構造一個保存 time stamp 值的對象。
此函數會根據給定的 ticks 值來構造一個保存 data 值的對象。ticks 是自紀元(epoch)以來秒數,詳見 the standard Python time module
此函數會根據給定的 ticks 值來構造一個保存 time 值的對象。ticks 是自紀元(epoch)以來秒數,詳見 the standard Python time module
此函數會根據給定的 ticks 值來構造一個保存 time stamp 值的對象。ticks 是自紀元(epoch)以來秒數,詳見 the standard Python time module
Binary(string)
此函數會構造一個可以保存 binary (long) 字符串值的對象。
# Binary's source code in pymysql def Binary(x): """Return x as a binary type.""" if PY2: return bytearray(x) else: return bytes(x)
詳見筆記: ﹝bytes.md﹞
在輸入/輸出中,SQL 的 NULL
值會表示爲 Python 的 None
單例對象。
⚠: 在數據庫接口中使用 Unix ticks 可能會致使沒必要要的麻煩,由於 Unix ticks 僅覆蓋有限的日期範圍
Cursor 對象的 .descripton
字段會返回"查詢結果"中每一列的相關信息,其中的 type_code
必須等於下述某個 Type Object,同一個 Type Object 可能會與多個類型代碼(type code)相等 (e.g. DATETIME
could be equal to the type codes for date, time and timestamp columns; see the Implementation Hints below for details).
模塊將包含如下單例(singleton)形式的 Type Object:
此 Type Object 用於描述數據庫中的 string-based 列,如 CHAR
此 Type Object 用於描述數據庫中的 (long) binary 列,如 LONG
, RAW
, BLOB
此 Type Object 用於描述數據庫中的 numeric 列
此 Type Object 用於描述數據庫中的 date/time 列
此 Type Object 用於描述數據庫中的 "Row ID" 列
譯者注: 這部份內容是給模塊的實現者的一些建議。若是你是模塊的使用者,無需過度關心這部份內容,隨意瀏覽一下就好,原文內容也比較簡單,所以我沒有進行翻譯。若是你想了解模塊的具體實現過程,那麼建議你仔細看一看。
Here is a sample implementation of the Unix ticks based constructors for date/time delegating work to the generic constructors:
import time def DateFromTicks(ticks): return Date(*time.localtime(ticks)[:3]) def TimeFromTicks(ticks): return Time(*time.localtime(ticks)[3:6]) def TimestampFromTicks(ticks): return Timestamp(*time.localtime(ticks)[:6])
Include/bufferobject.h
and Objects/bufferobject.c
in the Python source distribution.This Python class allows implementing the above type objects even though the description type code field yields multiple values for on type object:
class DBAPITypeObject: def __init__(self,*values): self.values = values def __cmp__(self,other): if other in self.values: return 0 if other < self.values: return 1 else: return -1
The resulting type object compares equal to all values passed to the constructor.
Here is a snippet of Python code that implements the exception hierarchy defined above:
import exceptions class Error(exceptions.StandardError): pass class Warning(exceptions.StandardError): pass class InterfaceError(Error): pass class DatabaseError(Error): pass class InternalError(DatabaseError): pass class OperationalError(DatabaseError): pass class ProgrammingError(DatabaseError): pass class IntegrityError(DatabaseError): pass class DataError(DatabaseError): pass class NotSupportedError(DatabaseError): pass
In C you can use the PyErr_NewException(fullname, base, NULL)
API to create the exception objects.
在 DB API 2.0 的生命週期中,模塊編寫者常常會編寫超出 DB API 2.0 規範的實現。爲了加強兼容性並(爲本規範的將來版本)提供乾淨的升級路徑,本節爲核心 DB API 2.0 規範定義了一組通用擴展。
與全部 DB API 可選功能同樣,數據庫模塊的編寫者能夠自由決定是否須要實現這些額外的字段和方法。若是調用了未實現的屬性,則會拋出 AttributeError
;對於只能在運行時才能檢查可用性的屬性,則會拋出 NotSupportedError 。
爲了讓模塊使用者哪些擴展 API 可用,建議模塊編寫者經過 Python warning 框架向程序員發出 Python warning。爲了使 warning 功能可用,必須對警告消息進行標準化,以便可以屏蔽它們。「標準的消息」是指下述內容中提到的 Warning Message 。
只讀屬性,表示 cursor 在當前結果集中的索引位置(起點是 0)。若是沒法肯定索引位置,則會返回 None
。
索引位置是指 cursor 在序列(結果集)中的位置。下一次 fetch 操做將獲取序列(結果集)中第 .rownumber
行。
Warning Message: "DB-API extension cursor.connection used"
全部按照 DB API 標準定義的異常類都應做爲 Connection
對象的屬性對外公開(在模塊做用域可用的除外)。
這些屬性可簡化多鏈接(multi-connection)環境中的錯誤除了。
Warning Message: "DB-API extension connection.<exception> used"
只讀屬性,返回建立 Cursor 對象的 Connection 對象的引用。
該屬性可簡化在多鏈接(multi-connection)環境中編寫多態(polymorph)代碼的過程。
Warning Message: "DB-API extension cursor.connection used"
🧩Cursor.scroll(value [, mode='relative' ])
改變 cursor 在結果集中的索引位置。
若是 mode='relative'
(默認狀況),則將 value 視做結果集中當前位置的偏移量;若是 mode='absolute'
,則將 value 視做結果集中的絕對目標位置。
NoteThis method should use native scrollable cursors, if available, or revert to an emulation for forward-only scrollable cursors. The method may raise NotSupportedError to signal that a specific operation is not supported by the database (e.g. backward scrolling).
Warning Message: "DB-API extension cursor.scroll() used"
該字段是一個 list
對象,從 cursor 的底層數據庫中接受到的全部消息(異常類、異常值)都會以元組形式追加到 .messages
列表中。
在調用各類標準的 cursor 方法時(.fetch*()
除外)都會自動清理 .messages
列表,從而避免佔用過多的內存。還可用經過 del cursor.messages[:]
手動清理 .messages
列表。
由數據庫生成的全部 error 和 warning 消息都會被放 .messages
列表中,所以用戶能夠經過檢查 .messages
來覈查 cursor 方法調用的 SQL 操做是否正確。
使用 .messages
的目的是消除對 Warning 異常的需求(某些 warning 實際上只包含信息字符)
Warning Message: "DB-API extension cursor.messages used"
與 Cursor.messages
相同,不過列表中的信息是面向 connection 的。
在調用各類標準的 connection 方法時(執行調用以前)都會自動清理 .messages
列表,從而避免佔用過多的內存。還可用經過 del connection.messages[:]
手動清理 .messages
列表。
Warning Message: "DB-API extension connection.messages used"
🧩Cursor.next()
與 .fetchone()
擁有相同的語義——從當前執行的 SQL 語句中返回下一行。在高於 Python 2.2 版本中,當結果集耗盡時會拋出 StopIteration
異常;在低於 Python 2.2 的版本中沒有 StopIteration
異常,可使用 IndexError
替代。實例:
# source code in mysql.connector def next(self): """Used for iterating over the result set.""" return self.__next__() def __next__(self): """ Used for iterating over the result set. Calles self.fetchone() to get the next row. """ try: row = self.fetchone() except errors.InterfaceError: raise StopIteration if not row: raise StopIteration return row
Warning Message: "DB-API extension cursor.next() used"
🧩Cursor.__iter__()
讓 cursors 對象兼容迭代器協議。
譯者注: 若是 Cursor 實現了 __next__()
,直接返回 self
便可;若是沒有實現,則須要返回一個可迭代對象,例如:
# source code in mysql.connector def __iter__(self): """ Iteration over the result set which calls self.fetchone() and returns the next row. """ return iter(self.fetchone, None)
註釋:Implementation Note: Python C extensions will have to implement the
tp_iter
slot on the cursor object instead of the.__iter__()
method.
Warning Message: "DB-API extension cursor.__iter__() used"
只讀屬性,將提供最近一次修改的行的 rowid (大多數數據庫僅在執行單個 INSERT
操做時會返回 rowid)。若是 SQL 操做未設置 rowid,或者數據庫不支持 rowid,則會將該屬性設置爲 None
。
若是最後一次執行的 SQL 語句修改了多個行,此時 .lastrowid
的語言沒法定義。例如,用 executemany()
執行 INSERT
語句。
Warning Message: "DB-API extension cursor.lastrowid used"
核心 DB API 規範僅引入了一組異常,在某些狀況下,異常可能對程序的流程形成極大的破壞,甚至會致使沒法執行。
對於這種狀況,爲了簡化處理數據庫時的錯誤處理(error handling),數據庫模塊的做者能夠選擇是否實現可以由用戶自定義的錯誤處理器(handler)。本節將介紹定義這些錯誤處理器的標準方法。
在建立 cursor 時,cursor 應從 connection 對象處繼承 .errorhandler
的設置。
🧩Connection.errorhandler, Cursor.errorhandler
以上兩個屬性均是可讀/寫屬性,它們被用來引用一個錯誤處理器,以便在知足錯誤條件時調用。
錯誤處理程序必須是一個可調用的 Python 對象,且具有如下參數:
errorhandler(connection, cursor, errorclass, errorvalue)
參數說明:
connection
- cursor 操做所屬的 connection 對象cursor
- cursor 對象,若是錯誤處理器不會應用於 cursor 對象,則實參值爲 None
errorclass
- error 類,會使用 errorvalue
做爲構造參數進行實例化標準錯誤處理器應將錯誤信息添加到相應的 .messages
屬性(Connection.messages
或Cursor.messages
),並拋出由 errorclass
和 errorvalue
定的異常。
若是沒有設置 .errorhandler
(即該字段值是 None
),則會採用外層的標準錯誤處理方案。
Warning Message: "DB-API extension .errorhandler used"
—— Optional Two-Phase Commit Extensions
許多數據庫都支持"二階段提交(two-phase commit - TPC)"。TPC 容許在管理事務時能夠跨多個數據庫鏈接和其它資源。
❓Q: 什麼是 TPC ?
A: 二階段提交(英語:Two-phase Commit)是指在計算機網絡以及數據庫領域內,爲了使基於分佈式系統架構下的全部節點在進行事務提交時保持一致性而設計的一種算法。另見:
若是數據庫後端支持 TPC,而且數據庫模塊的做者但願公開支持 TPC,則應實現如下 API。若是隻能在運行時才能檢查數據庫後端對 TPC 的支持,當遇到不支持的狀況時,應拋出 NotSupportedError
。
—— TPC 事務 ID
大多數數據庫都遵循 XA 規範,所以 transaction ID 應包含如下三個組件:
對於特定的全局事務(global transaction),前兩個組件對於全部資源應該都是相同的。應爲全局事務中的每一個資源分配不一樣的 branch qualifier。
上述組件必須知足如下標準:
應使用 .xid()
Connection 方法建立 transaction ID:
返回一個適合傳遞給 connection 的 .tpc_*()
方法的自定義 transaction ID 對象。
若是數據鏈接不支持 TPC,應拋出 NotSupportedError
異常。
.xid()
返回的自定義 transaction ID 對象的類型,並無強制要求,但 transaction ID 對象必須具有"序列"行爲,並容許訪問其中的三個組件。一個合格的數據庫模塊在表示 transaction ID 時,應該既可使用自定義對象,也可使用 transaction ID。
使用指定的 xid (transaction ID) 來開始一個 TPC 事務。
調用此方法時,應位於事務的外部,即自上次調用 .commit()
或 rollback()
以來沒有執行過任何操做。
此外,在 TPC 事務中調用 .commit()
或 .rollback()
會致使 error。若是應用程序在激活 TPC 事務後調用 .commit()
或 .rollback()
,應拋出 ProgrammingError
異常。
若是數據庫鏈接不支持 TPC,應拋出 NotSupportedError
異常。
調用 .tpc_prepare()
開始一個 TPC 事務後,使用 .tpc_prepare()
來執行事務的第一階段。若是在 TPC 事務外部調用 .tpc_prepare()
,應拋出 ProgrammingError
異常。
在調用 .tpc_prepare()
以後,直至調用 .tpc_commit()
或 .tpc_rollback()
以前不能執行任何語句。
以無參數形式調用 .tpc_commit()
時,該方法會提交以前使用 .tpc_prepare()
準備的 TPC 事務。
若是在 .tpc_prepare()
以前調用 .tpc_commit()
,則會執行一個單階段提交(single phase commit)。若是僅有一個資源參與到全局事務中,那麼事務管理器能夠選擇執行此操做。
若是在調用 .tpc_commit()
時傳遞了 xid (transaction ID) ,數據庫則會提交指定的事務。若是所提供的 xid 無效,應拋出 ProgrammingError
異常。應在事務外部使用這種調用形式,用來執行恢復操做。
該方法返回時,表示 TPC 事務已結束。
以無參數形式調用 .rollback()
時,該方法會回滾一個 TPC 事務。在 .tpc_prepare()
先後都可調用 .rollback()
。
若是在調用 .rollback()
時傳遞了 xid (transaction ID) ,則會回滾指定事務。若是所提供的 xid 無效,應拋出 ProgrammingError
異常。應在事務外部使用這種調用形式,用來執行恢復操做。
該方法返回時,表示 TPC 事務已結束。
返回一個適用於 .tpc_commit(xid)
或 .tpc_rollback(xid)
的列表,列表中的項由掛起的 transaction ID 組成。
若是數據庫不支持事務恢復,應返回一個空列表,或拋出 NotSupportedError
異常。
在數據庫 SIG (Special Interest Groups - 特別興趣組) 中常常會重複出現一些與 DB API 規範相關的問題。本節將涵蓋一些與本規範相關的常見文通。
問: 如何從 .fetch*()
返回的元組中構造一個字典?
答: 有幾種現成的工具能夠幫你完成這項任務。這些工具大多會使用 cursor.description
屬性中定義的列名來做爲行字典的鍵。
爲何不擴展 DB API 規範,以使 fetch*()
返回字典形式的內容喃?由於這樣的作法存在如下弊端:
所以,在不一樣的數據庫中,用來訪問列的字典的鍵是不一樣的,這使得沒法編寫具有可移植性的代碼。
相較於 1.0 版,在 2.0 中引入了一些重大改動。2.0 中的某些改動將致使現有的基於 DB API 1.0 的腳本發生終端,所以調整了主版本號以反映此更改的力度。
從 1.0 和 2.0 到最重要的變化以下:
RAW
Type Object 被重命名爲 BINARY
。結果集應涵蓋現代 SQL 數據庫常見的全部基本數據類型。apilevel
, threadsfety
, paramstyle
)和方法(executemany()
, nextset()
),以便提供更好的數據庫綁定。.callproc()
的語義.execute()
返回值的定義。之前,返回值基於 SQL 語句類型,很難正確實現;如今,改成未定義。之前 .execute()
可能會返回結果集的行數,如今請使用 .rowcount
。模塊能夠自由返回舊樣式返回值,但這再也不是規範的強制要求的,應該被視爲依賴於數據庫接口。在 DB API 2.0 規範發佈後,添加的內容:
儘管 2.0 規範中澄清了 1.0 版中還沒有解決的許多問題,但仍有一些問題須要在將來版本中解決:
.nextset()
的返回值應能表現出新結果集的可用狀況