sqlite3 --- SQLite 數(shù)據(jù)庫(kù) DB-API 2.0 接口模塊?

源代碼: Lib/sqlite3/


SQLite 是一個(gè)C語(yǔ)言庫(kù),它可以提供一種輕量級(jí)的基于磁盤的數(shù)據(jù)庫(kù),這種數(shù)據(jù)庫(kù)不需要獨(dú)立的服務(wù)器進(jìn)程,也允許需要使用一種非標(biāo)準(zhǔn)的 SQL 查詢語(yǔ)言來(lái)訪問它。一些應(yīng)用程序可以使用 SQLite 作為內(nèi)部數(shù)據(jù)存儲(chǔ)。可以用它來(lái)創(chuàng)建一個(gè)應(yīng)用程序原型,然后再遷移到更大的數(shù)據(jù)庫(kù),比如 PostgreSQL 或 Oracle。

sqlite3 模塊由 Gerhard H?ring 編寫。它提供了符合 DB-API 2.0 規(guī)范的接口,這個(gè)規(guī)范是 PEP 249

要使用這個(gè)模塊,必須先創(chuàng)建一個(gè) Connection 對(duì)象,它代表數(shù)據(jù)庫(kù)。下面例子中,數(shù)據(jù)將存儲(chǔ)在 example.db 文件中:

import sqlite3
conn = sqlite3.connect('example.db')

你也可以使用 :memory: 來(lái)創(chuàng)建一個(gè)內(nèi)存中的數(shù)據(jù)庫(kù)

當(dāng)有了 Connection 對(duì)象后,你可以創(chuàng)建一個(gè) Cursor 游標(biāo)對(duì)象,然后調(diào)用它的 execute() 方法來(lái)執(zhí)行 SQL 語(yǔ)句:

c = conn.cursor()

# Create table
c.execute('''CREATE TABLE stocks
             (date text, trans text, symbol text, qty real, price real)''')

# Insert a row of data
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")

# Save (commit) the changes
conn.commit()

# We can also close the connection if we are done with it.
# Just be sure any changes have been committed or they will be lost.
conn.close()

這些數(shù)據(jù)被持久化保存了,而且可以在之后的會(huì)話中使用它們:

import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()

通常你的 SQL 操作需要使用一些 Python 變量的值。你不應(yīng)該使用 Python 的字符串操作來(lái)創(chuàng)建你的查詢語(yǔ)句,因?yàn)槟菢幼霾话踩?;它?huì)使你的程序容易受到 SQL 注入攻擊(在 https://xkcd.com/327/ 上有一個(gè)搞笑的例子,看看有什么后果)

推薦另外一種方法:使用 DB-API 的參數(shù)替換。在你的 SQL 語(yǔ)句中,使用 ? 占位符來(lái)代替值,然后把對(duì)應(yīng)的值組成的元組做為 execute() 方法的第二個(gè)參數(shù)。(其他數(shù)據(jù)庫(kù)可能會(huì)使用不同的占位符,比如 %s 或者 :1)例如:

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print(c.fetchone())

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

要在執(zhí)行 SELECT 語(yǔ)句后獲取數(shù)據(jù),你可以把游標(biāo)作為 iterator,然后調(diào)用它的 fetchone() 方法來(lái)獲取一條匹配的行,也可以調(diào)用 fetchall() 來(lái)得到包含多個(gè)匹配行的列表。

下面是一個(gè)使用迭代器形式的例子:

>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
        print(row)

('2006-01-05', 'BUY', 'RHAT', 100, 35.14)
('2006-03-28', 'BUY', 'IBM', 1000, 45.0)
('2006-04-06', 'SELL', 'IBM', 500, 53.0)
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)

參見

https://github.com/ghaering/pysqlite

pysqlite的主頁(yè) -- sqlite3 在外部使用 “pysqlite” 名字進(jìn)行開發(fā)。

https://www.sqlite.org

SQLite的主頁(yè);它的文檔詳細(xì)描述了它所支持的 SQL 方言的語(yǔ)法和可用的數(shù)據(jù)類型。

https://www.w3schools.com/sql/

學(xué)習(xí) SQL 語(yǔ)法的教程、參考和例子。

PEP 249 - DB-API 2.0 規(guī)范

Marc-André Lemburg 寫的 PEP。

模塊函數(shù)和常量?

sqlite3.version?

這個(gè)模塊的版本號(hào),是一個(gè)字符串。不是 SQLite 庫(kù)的版本號(hào)。

sqlite3.version_info?

這個(gè)模塊的版本號(hào),是一個(gè)由整數(shù)組成的元組。不是 SQLite 庫(kù)的版本號(hào)。

sqlite3.sqlite_version?

使用中的 SQLite 庫(kù)的版本號(hào),是一個(gè)字符串。

sqlite3.sqlite_version_info?

使用中的 SQLite 庫(kù)的版本號(hào),是一個(gè)整數(shù)組成的元組。

sqlite3.PARSE_DECLTYPES?

這個(gè)常量可以作為 connect() 函數(shù)的 detect_types 參數(shù)。

設(shè)置這個(gè)參數(shù)后,sqlite3 模塊將解析它返回的每一列申明的類型。它會(huì)申明的類型的第一個(gè)單詞,比如“integer primary key”,它會(huì)解析出“integer”,再比如“number(10)”,它會(huì)解析出“number”。然后,它會(huì)在轉(zhuǎn)換器字典里查找那個(gè)類型注冊(cè)的轉(zhuǎn)換器函數(shù),并調(diào)用它。

sqlite3.PARSE_COLNAMES?

這個(gè)常量可以作為 connect() 函數(shù)的 detect_types 參數(shù)。

設(shè)置此參數(shù)可使得 SQLite 接口解析它所返回的每一列的列名。 它將在其中查找形式為 [mytype] 的字符串,然后將 'mytype' 確定為列的類型。 它將嘗試在轉(zhuǎn)換器字典中查找 'mytype' 條目,然后用找到的轉(zhuǎn)換器函數(shù)來(lái)返回值。 在 Cursor.description 中找到的列名并不包括類型,舉例來(lái)說,如果你在你的 SQL 中使用了像 'as "Expiration date [datetime]"' 這樣的寫法,那么我們將解析出在第一個(gè) then we will parse out everything until the first '[' 之前的所有內(nèi)容并去除前導(dǎo)空格作為列名:即列名將為 "Expiration date"。

sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])?

連接 SQLite 數(shù)據(jù)庫(kù) database。默認(rèn)返回 Connection 對(duì)象,除非使用了自定義的 factory 參數(shù)。

database 是準(zhǔn)備打開的數(shù)據(jù)庫(kù)文件的路徑(絕對(duì)路徑或相對(duì)于當(dāng)前目錄的相對(duì)路徑),它是 path-like object。你也可以用 ":memory:" 在內(nèi)存中打開一個(gè)數(shù)據(jù)庫(kù)。

當(dāng)一個(gè)數(shù)據(jù)庫(kù)被多個(gè)連接訪問的時(shí)候,如果其中一個(gè)進(jìn)程修改這個(gè)數(shù)據(jù)庫(kù),在這個(gè)事務(wù)提交之前,這個(gè) SQLite 數(shù)據(jù)庫(kù)將會(huì)被一直鎖定。timeout 參數(shù)指定了這個(gè)連接等待鎖釋放的超時(shí)時(shí)間,超時(shí)之后會(huì)引發(fā)一個(gè)異常。這個(gè)超時(shí)時(shí)間默認(rèn)是 5.0(5秒)。

isolation_level 參數(shù),請(qǐng)查看 Connection 對(duì)象的 isolation_level 屬性。

SQLite 原生只支持5種類型:TEXT,INTEGER,REAL,BLOB 和 NULL。如果你想用其它類型,你必須自己添加相應(yīng)的支持。使用 detect_types 參數(shù)和模塊級(jí)別的 register_converter() 函數(shù)注冊(cè)**轉(zhuǎn)換器** 可以簡(jiǎn)單的實(shí)現(xiàn)。

detect_types 默認(rèn)為0(即關(guān)閉,沒有類型檢測(cè))。你也可以組合 PARSE_DECLTYPESPARSE_COLNAMES 來(lái)開啟類型檢測(cè)。

默認(rèn)情況下,check_same_threadTrue,只有當(dāng)前的線程可以使用該連接。 如果設(shè)置為 False,則多個(gè)線程可以共享返回的連接。 當(dāng)多個(gè)線程使用同一個(gè)連接的時(shí)候,用戶應(yīng)該把寫操作進(jìn)行序列化,以避免數(shù)據(jù)損壞。

默認(rèn)情況下,當(dāng)調(diào)用 connect 方法的時(shí)候,sqlite3 模塊使用了它的 Connection 類。當(dāng)然,你也可以創(chuàng)建 Connection 類的子類,然后創(chuàng)建提供了 factory 參數(shù)的 connect() 方法。

詳情請(qǐng)查閱當(dāng)前手冊(cè)的 SQLite 與 Python 類型 部分。

sqlite3 模塊在內(nèi)部使用語(yǔ)句緩存來(lái)避免 SQL 解析開銷。 如果要顯式設(shè)置當(dāng)前連接可以緩存的語(yǔ)句數(shù),可以設(shè)置 cached_statements 參數(shù)。 當(dāng)前實(shí)現(xiàn)的默認(rèn)值是緩存100條語(yǔ)句。

如果 uri 為真,則 database 被解釋為 URI。 它允許您指定選項(xiàng)。 例如,以只讀模式打開數(shù)據(jù)庫(kù):

db = sqlite3.connect('file:path/to/database?mode=ro', uri=True)

有關(guān)此功能的更多信息,包括已知選項(xiàng)的列表,可以在 ` SQLite URI 文檔 <https://www.sqlite.org/uri.html>`_ 中找到。

在 3.4 版更改: 增加了 uri 參數(shù)。

在 3.7 版更改: database 現(xiàn)在可以是一個(gè) path-like object 對(duì)象了,不僅僅是字符串。

sqlite3.register_converter(typename, callable)?

注冊(cè)一個(gè)回調(diào)對(duì)象 callable, 用來(lái)轉(zhuǎn)換數(shù)據(jù)庫(kù)中的字節(jié)串為自定的 Python 類型。所有類型為 typename 的數(shù)據(jù)庫(kù)的值在轉(zhuǎn)換時(shí),都會(huì)調(diào)用這個(gè)回調(diào)對(duì)象。通過指定 connect() 函數(shù)的 detect-types 參數(shù)來(lái)設(shè)置類型檢測(cè)的方式。注意,typename 與查詢語(yǔ)句中的類型名進(jìn)行匹配時(shí)不區(qū)分大小寫。

sqlite3.register_adapter(type, callable)?

注冊(cè)一個(gè)回調(diào)對(duì)象 callable,用來(lái)轉(zhuǎn)換自定義Python類型為一個(gè) SQLite 支持的類型。 這個(gè)回調(diào)對(duì)象 callable 僅接受一個(gè) Python 值作為參數(shù),而且必須返回以下某個(gè)類型的值:int,float,str 或 bytes。

sqlite3.complete_statement(sql)?

如果字符串 sql 包含一個(gè)或多個(gè)完整的 SQL 語(yǔ)句(以分號(hào)結(jié)束)則返回 True。它不會(huì)驗(yàn)證 SQL 語(yǔ)法是否正確,僅會(huì)驗(yàn)證字符串字面上是否完整,以及是否以分號(hào)結(jié)束。

它可以用來(lái)構(gòu)建一個(gè) SQLite shell,下面是一個(gè)例子:

# A minimal SQLite shell for experiments

import sqlite3

con = sqlite3.connect(":memory:")
con.isolation_level = None
cur = con.cursor()

buffer = ""

print("Enter your SQL commands to execute in sqlite3.")
print("Enter a blank line to exit.")

while True:
    line = input()
    if line == "":
        break
    buffer += line
    if sqlite3.complete_statement(buffer):
        try:
            buffer = buffer.strip()
            cur.execute(buffer)

            if buffer.lstrip().upper().startswith("SELECT"):
                print(cur.fetchall())
        except sqlite3.Error as e:
            print("An error occurred:", e.args[0])
        buffer = ""

con.close()
sqlite3.enable_callback_tracebacks(flag)?

默認(rèn)情況下,您不會(huì)獲得任何用戶定義函數(shù)中的回溯消息,比如聚合,轉(zhuǎn)換器,授權(quán)器回調(diào)等。如果要調(diào)試它們,可以設(shè)置 flag 參數(shù)為 True 并調(diào)用此函數(shù)。 之后,回調(diào)中的回溯信息將會(huì)輸出到 sys.stderr。 再次使用 False 來(lái)禁用該功能。

連接對(duì)象(Connection)?

class sqlite3.Connection?

SQLite 數(shù)據(jù)庫(kù)連接對(duì)象有如下的屬性和方法:

isolation_level?

獲取或設(shè)置當(dāng)前默認(rèn)的隔離級(jí)別。 表示自動(dòng)提交模式的 None 以及 "DEFERRED", "IMMEDIATE" 或 "EXCLUSIVE" 其中之一。 詳細(xì)描述請(qǐng)參閱 控制事務(wù)。

in_transaction?

如果是在活動(dòng)事務(wù)中(還沒有提交改變),返回 True,否則,返回 False。它是一個(gè)只讀屬性。

3.2 新版功能.

cursor(factory=Cursor)?

這個(gè)方法接受一個(gè)可選參數(shù) factory,如果要指定這個(gè)參數(shù),它必須是一個(gè)可調(diào)用對(duì)象,而且必須返回 Cursor 類的一個(gè)實(shí)例或者子類。

commit()?

這個(gè)方法提交當(dāng)前事務(wù)。如果沒有調(diào)用這個(gè)方法,那么從上一次提交 commit() 以來(lái)所有的變化在其他數(shù)據(jù)庫(kù)連接上都是不可見的。如果你往數(shù)據(jù)庫(kù)里寫了數(shù)據(jù),但是又查詢不到,請(qǐng)檢查是否忘記了調(diào)用這個(gè)方法。

rollback()?

這個(gè)方法回滾從上一次調(diào)用 commit() 以來(lái)所有數(shù)據(jù)庫(kù)的改變。

close()?

關(guān)閉數(shù)據(jù)庫(kù)連接。注意,它不會(huì)自動(dòng)調(diào)用 commit() 方法。如果在關(guān)閉數(shù)據(jù)庫(kù)連接之前沒有調(diào)用 commit(),那么你的修改將會(huì)丟失!

execute(sql[, parameters])?

這是一個(gè)非標(biāo)準(zhǔn)的快捷方法,它會(huì)調(diào)用 cursor() 方法來(lái)創(chuàng)建一個(gè)游標(biāo)對(duì)象,并使用給定的 parameters 參數(shù)來(lái)調(diào)用游標(biāo)對(duì)象的 execute() 方法,最后返回這個(gè)游標(biāo)對(duì)象。

executemany(sql[, parameters])?

這是一個(gè)非標(biāo)準(zhǔn)的快捷方法,它會(huì)調(diào)用 cursor() 方法來(lái)創(chuàng)建一個(gè)游標(biāo)對(duì)象,并使用給定的 parameters 參數(shù)來(lái)調(diào)用游標(biāo)對(duì)象的 executemany() 方法,最后返回這個(gè)游標(biāo)對(duì)象。

executescript(sql_script)?

這是一個(gè)非標(biāo)準(zhǔn)的快捷方法,它會(huì)調(diào)用 cursor() 方法來(lái)創(chuàng)建一個(gè)游標(biāo)對(duì)象,并使用給定的 sql_script 參數(shù)來(lái)調(diào)用游標(biāo)對(duì)象的 executescript() 方法,最后返回這個(gè)游標(biāo)對(duì)象。

create_function(name, num_params, func)?

創(chuàng)建一個(gè)可以在 SQL 語(yǔ)句中使用的自定義函數(shù),其中參數(shù) name 為 SQL 語(yǔ)句中使用的函數(shù)名,num_params 是這個(gè)函數(shù)接受的參數(shù)個(gè)數(shù)(如果 num_params 為 -1,那這個(gè)函數(shù)可以接受任意數(shù)量的參數(shù)),最后一個(gè)參數(shù) func 是作為 SQL 函數(shù)調(diào)用的一個(gè) Python 可調(diào)用對(duì)象。

此函數(shù)可返回任何 SQLite 所支持的類型: bytes, str, int, float 和 None

示例:

import sqlite3
import hashlib

def md5sum(t):
    return hashlib.md5(t).hexdigest()

con = sqlite3.connect(":memory:")
con.create_function("md5", 1, md5sum)
cur = con.cursor()
cur.execute("select md5(?)", (b"foo",))
print(cur.fetchone()[0])

con.close()
create_aggregate(name, num_params, aggregate_class)?

創(chuàng)建一個(gè)自定義的聚合函數(shù)。

參數(shù)中 aggregate_class 類必須實(shí)現(xiàn)兩個(gè)方法:stepfinalizestep 方法接受 num_params 個(gè)參數(shù)(如果 num_params 為 -1,那么這個(gè)函數(shù)可以接受任意數(shù)量的參數(shù));finalize 方法返回最終的聚合結(jié)果。

finalize 方法可以返回任何 SQLite 支持的類型:bytes,str,int,float 和 None。

示例:

import sqlite3

class MySum:
    def __init__(self):
        self.count = 0

    def step(self, value):
        self.count += value

    def finalize(self):
        return self.count

con = sqlite3.connect(":memory:")
con.create_aggregate("mysum", 1, MySum)
cur = con.cursor()
cur.execute("create table test(i)")
cur.execute("insert into test(i) values (1)")
cur.execute("insert into test(i) values (2)")
cur.execute("select mysum(i) from test")
print(cur.fetchone()[0])

con.close()
create_collation(name, callable)?

使用 namecallable 創(chuàng)建排序規(guī)則。這個(gè) callable 接受兩個(gè)字符串對(duì)象,如果第一個(gè)小于第二個(gè)則返回 -1, 如果兩個(gè)相等則返回 0,如果第一個(gè)大于第二個(gè)則返回 1。注意,這是用來(lái)控制排序的(SQL 中的 ORDER BY),所以它不會(huì)影響其它的 SQL 操作。

注意,這個(gè) callable 可調(diào)用對(duì)象會(huì)把它的參數(shù)作為 Python 字節(jié)串,通常會(huì)以 UTF-8 編碼格式對(duì)它進(jìn)行編碼。

以下示例顯示了使用“錯(cuò)誤方式”進(jìn)行排序的自定義排序規(guī)則:

import sqlite3

def collate_reverse(string1, string2):
    if string1 == string2:
        return 0
    elif string1 < string2:
        return 1
    else:
        return -1

con = sqlite3.connect(":memory:")
con.create_collation("reverse", collate_reverse)

cur = con.cursor()
cur.execute("create table test(x)")
cur.executemany("insert into test(x) values (?)", [("a",), ("b",)])
cur.execute("select x from test order by x collate reverse")
for row in cur:
    print(row)
con.close()

要移除一個(gè)排序規(guī)則,需要調(diào)用 create_collation 并設(shè)置 callable 參數(shù)為 None

con.create_collation("reverse", None)
interrupt()?

可以從不同的線程調(diào)用這個(gè)方法來(lái)終止所有查詢操作,這些查詢操作可能正在連接上執(zhí)行。此方法調(diào)用之后, 查詢將會(huì)終止,而且查詢的調(diào)用者會(huì)獲得一個(gè)異常。

set_authorizer(authorizer_callback)?

此方法注冊(cè)一個(gè)授權(quán)回調(diào)對(duì)象。每次在訪問數(shù)據(jù)庫(kù)中某個(gè)表的某一列的時(shí)候,這個(gè)回調(diào)對(duì)象將會(huì)被調(diào)用。如果要允許訪問,則返回 SQLITE_OK,如果要終止整個(gè) SQL 語(yǔ)句,則返回 SQLITE_DENY,如果這一列需要當(dāng)做 NULL 值處理,則返回 SQLITE_IGNORE。這些常量可以在 sqlite3 模塊中找到。

回調(diào)的第一個(gè)參數(shù)表示要授權(quán)的操作類型。 第二個(gè)和第三個(gè)參數(shù)將是參數(shù)或 None,具體取決于第一個(gè)參數(shù)的值。 第 4 個(gè)參數(shù)是數(shù)據(jù)庫(kù)的名稱(“main”,“temp”等),如果需要的話。 第 5 個(gè)參數(shù)是負(fù)責(zé)訪問嘗試的最內(nèi)層觸發(fā)器或視圖的名稱,或者如果此訪問嘗試直接來(lái)自輸入 SQL 代碼,則為 None。

請(qǐng)參閱 SQLite 文檔,了解第一個(gè)參數(shù)的可能值以及第二個(gè)和第三個(gè)參數(shù)的含義,具體取決于第一個(gè)參數(shù)。 所有必需的常量都可以在 sqlite3 模塊中找到。

set_progress_handler(handler, n)?

此例程注冊(cè)回調(diào)。 對(duì)SQLite虛擬機(jī)的每個(gè)多指令調(diào)用回調(diào)。 如果要在長(zhǎng)時(shí)間運(yùn)行的操作期間從SQLite調(diào)用(例如更新用戶界面),這非常有用。

如果要清除以前安裝的任何進(jìn)度處理程序,調(diào)用該方法時(shí)請(qǐng)將 handler 參數(shù)設(shè)置為 None

從處理函數(shù)返回非零值將終止當(dāng)前正在執(zhí)行的查詢并導(dǎo)致它引發(fā) OperationalError 異常。

set_trace_callback(trace_callback)?

為每個(gè) SQLite 后端實(shí)際執(zhí)行的 SQL 語(yǔ)句注冊(cè)要調(diào)用的 trace_callback。

傳遞給回調(diào)的唯一參數(shù)是正在執(zhí)行的語(yǔ)句(作為字符串)。 回調(diào)的返回值將被忽略。 請(qǐng)注意,后端不僅運(yùn)行傳遞給 Cursor.execute() 方法的語(yǔ)句。 其他來(lái)源包括 Python 模塊的事務(wù)管理和當(dāng)前數(shù)據(jù)庫(kù)中定義的觸發(fā)器的執(zhí)行。

將傳入的 trace_callback 設(shè)為 None 將禁用跟蹤回調(diào)。

3.3 新版功能.

enable_load_extension(enabled)?

此例程允許/禁止SQLite引擎從共享庫(kù)加載SQLite擴(kuò)展。 SQLite擴(kuò)展可以定義新功能,聚合或全新的虛擬表實(shí)現(xiàn)。 一個(gè)眾所周知的擴(kuò)展是與SQLite一起分發(fā)的全文搜索擴(kuò)展。

默認(rèn)情況下禁用可加載擴(kuò)展。 見 1.

3.2 新版功能.

import sqlite3

con = sqlite3.connect(":memory:")

# enable extension loading
con.enable_load_extension(True)

# Load the fulltext search extension
con.execute("select load_extension('./fts3.so')")

# alternatively you can load the extension using an API call:
# con.load_extension("./fts3.so")

# disable extension loading again
con.enable_load_extension(False)

# example from SQLite wiki
con.execute("create virtual table recipe using fts3(name, ingredients)")
con.executescript("""
    insert into recipe (name, ingredients) values ('broccoli stew', 'broccoli peppers cheese tomatoes');
    insert into recipe (name, ingredients) values ('pumpkin stew', 'pumpkin onions garlic celery');
    insert into recipe (name, ingredients) values ('broccoli pie', 'broccoli cheese onions flour');
    insert into recipe (name, ingredients) values ('pumpkin pie', 'pumpkin sugar flour butter');
    """)
for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"):
    print(row)

con.close()
load_extension(path)?

此例程從共享庫(kù)加載SQLite擴(kuò)展。 在使用此例程之前,必須使用 enable_load_extension() 啟用擴(kuò)展加載。

默認(rèn)情況下禁用可加載擴(kuò)展。 見 1.

3.2 新版功能.

row_factory?

您可以將此屬性更改為可接受游標(biāo)和原始行作為元組的可調(diào)用對(duì)象,并將返回實(shí)際結(jié)果行。 這樣,您可以實(shí)現(xiàn)更高級(jí)的返回結(jié)果的方法,例如返回一個(gè)可以按名稱訪問列的對(duì)象。

示例:

import sqlite3

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

con = sqlite3.connect(":memory:")
con.row_factory = dict_factory
cur = con.cursor()
cur.execute("select 1 as a")
print(cur.fetchone()["a"])

con.close()

如果返回一個(gè)元組是不夠的,并且你想要對(duì)列進(jìn)行基于名稱的訪問,你應(yīng)該考慮將 row_factory 設(shè)置為高度優(yōu)化的 sqlite3.Row 類型。 Row 提供基于索引和不區(qū)分大小寫的基于名稱的訪問,幾乎沒有內(nèi)存開銷。 它可能比您自己的基于字典的自定義方法甚至基于 db_row 的解決方案更好。

text_factory?

使用此屬性可以控制為 TEXT 數(shù)據(jù)類型返回的對(duì)象。 默認(rèn)情況下,此屬性設(shè)置為 strsqlite3 模塊將返回 TEXT 的 Unicode 對(duì)象。 如果要返回字節(jié)串,可以將其設(shè)置為 bytes。

您還可以將其設(shè)置為接受單個(gè) bytestring 參數(shù)的任何其他可調(diào)用對(duì)象,并返回結(jié)果對(duì)象。

請(qǐng)參閱以下示例代碼以進(jìn)行說明:

import sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()

AUSTRIA = "\xd6sterreich"

# by default, rows are returned as Unicode
cur.execute("select ?", (AUSTRIA,))
row = cur.fetchone()
assert row[0] == AUSTRIA

# but we can make sqlite3 always return bytestrings ...
con.text_factory = bytes
cur.execute("select ?", (AUSTRIA,))
row = cur.fetchone()
assert type(row[0]) is bytes
# the bytestrings will be encoded in UTF-8, unless you stored garbage in the
# database ...
assert row[0] == AUSTRIA.encode("utf-8")

# we can also implement a custom text_factory ...
# here we implement one that appends "foo" to all strings
con.text_factory = lambda x: x.decode("utf-8") + "foo"
cur.execute("select ?", ("bar",))
row = cur.fetchone()
assert row[0] == "barfoo"

con.close()
total_changes?

返回自打開數(shù)據(jù)庫(kù)連接以來(lái)已修改,插入或刪除的數(shù)據(jù)庫(kù)行的總數(shù)。

iterdump()?

返回以SQL文本格式轉(zhuǎn)儲(chǔ)數(shù)據(jù)庫(kù)的迭代器。 保存內(nèi)存數(shù)據(jù)庫(kù)以便以后恢復(fù)時(shí)很有用。 此函數(shù)提供與 sqlite3 shell 中的 .dump 命令相同的功能。

示例:

# Convert file existing_db.db to SQL dump file dump.sql
import sqlite3

con = sqlite3.connect('existing_db.db')
with open('dump.sql', 'w') as f:
    for line in con.iterdump():
        f.write('%s\n' % line)
con.close()
backup(target, *, pages=0, progress=None, name="main", sleep=0.250)?

即使在 SQLite 數(shù)據(jù)庫(kù)被其他客戶端訪問時(shí),或者同時(shí)由同一連接訪問,該方法也會(huì)對(duì)其進(jìn)行備份。 該副本將寫入強(qiáng)制參數(shù) target,該參數(shù)必須是另一個(gè) Connection 實(shí)例。

默認(rèn)情況下,或者當(dāng) pages0 或負(fù)整數(shù)時(shí),整個(gè)數(shù)據(jù)庫(kù)將在一個(gè)步驟中復(fù)制;否則該方法一次循環(huán)復(fù)制 pages 規(guī)定數(shù)量的頁(yè)面。

如果指定了 progress,則它必須為 None 或一個(gè)將在每次迭代時(shí)附帶三個(gè)整數(shù)參數(shù)執(zhí)行的可調(diào)用對(duì)象,這三個(gè)參數(shù)分別是前一次迭代的狀態(tài) status,將要拷貝的剩余頁(yè)數(shù) remaining 以及總頁(yè)數(shù) total。

name 參數(shù)指定將被拷貝的數(shù)據(jù)庫(kù)名稱:它必須是一個(gè)字符串,其內(nèi)容為表示主數(shù)據(jù)庫(kù)的默認(rèn)值 "main",表示臨時(shí)數(shù)據(jù)庫(kù)的 "temp" 或是在 ATTACH DATABASE 語(yǔ)句的 AS 關(guān)鍵字之后指定表示附加數(shù)據(jù)庫(kù)的名稱。

sleep 參數(shù)指定在備份剩余頁(yè)的連續(xù)嘗試之間要休眠的秒數(shù),可以指定為一個(gè)整數(shù)或一個(gè)浮點(diǎn)數(shù)值。

示例一,將現(xiàn)有數(shù)據(jù)庫(kù)復(fù)制到另一個(gè)數(shù)據(jù)庫(kù)中:

import sqlite3

def progress(status, remaining, total):
    print(f'Copied {total-remaining} of {total} pages...')

con = sqlite3.connect('existing_db.db')
bck = sqlite3.connect('backup.db')
with bck:
    con.backup(bck, pages=1, progress=progress)
bck.close()
con.close()

示例二,將現(xiàn)有數(shù)據(jù)庫(kù)復(fù)制到臨時(shí)副本中:

import sqlite3

source = sqlite3.connect('existing_db.db')
dest = sqlite3.connect(':memory:')
source.backup(dest)

可用性:SQLite 3.6.11 或以上版本

3.7 新版功能.

Cursor 對(duì)象?

class sqlite3.Cursor?

Cursor 游標(biāo)實(shí)例具有以下屬性和方法。

execute(sql[, parameters])?

執(zhí)行SQL語(yǔ)句。 可以是參數(shù)化 SQL 語(yǔ)句(即,在 SQL 語(yǔ)句中使用占位符)。sqlite3 模塊支持兩種占位符:?jiǎn)柼?hào)(qmark風(fēng)格)和命名占位符(命名風(fēng)格)。

以下是兩種風(fēng)格的示例:

import sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table people (name_last, age)")

who = "Yeltsin"
age = 72

# This is the qmark style:
cur.execute("insert into people values (?, ?)", (who, age))

# And this is the named style:
cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age})

print(cur.fetchone())

con.close()

execute() 將只執(zhí)行一條單獨(dú)的 SQL 語(yǔ)句。 如果你嘗試用它執(zhí)行超過一條語(yǔ)句,將會(huì)引發(fā) Warning。 如果你想要用一次調(diào)用執(zhí)行多條 SQL 語(yǔ)句請(qǐng)使用 executescript()

executemany(sql, seq_of_parameters)?

基于在序列 seq_of_parameters 中找到的所有形參序列或映射執(zhí)行一條 SQL 命令。 sqlite3 模塊還允許使用 iterator 代替序列來(lái)產(chǎn)生形參。

import sqlite3

class IterChars:
    def __init__(self):
        self.count = ord('a')

    def __iter__(self):
        return self

    def __next__(self):
        if self.count > ord('z'):
            raise StopIteration
        self.count += 1
        return (chr(self.count - 1),) # this is a 1-tuple

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table characters(c)")

theIter = IterChars()
cur.executemany("insert into characters(c) values (?)", theIter)

cur.execute("select c from characters")
print(cur.fetchall())

con.close()

這是一個(gè)使用生成器 generator 的簡(jiǎn)短示例:

import sqlite3
import string

def char_generator():
    for c in string.ascii_lowercase:
        yield (c,)

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table characters(c)")

cur.executemany("insert into characters(c) values (?)", char_generator())

cur.execute("select c from characters")
print(cur.fetchall())

con.close()
executescript(sql_script)?

這是一個(gè)非標(biāo)準(zhǔn)的便捷方法,可用于一次執(zhí)行多條 SQL 語(yǔ)句。 它會(huì)首先執(zhí)行一條 COMMIT 語(yǔ)句,再執(zhí)行以形參方式獲取的 SQL 腳本。

sql_script 可以是一個(gè) str 類的實(shí)例。

示例:

import sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.executescript("""
    create table person(
        firstname,
        lastname,
        age
    );

    create table book(
        title,
        author,
        published
    );

    insert into book(title, author, published)
    values (
        'Dirk Gently''s Holistic Detective Agency',
        'Douglas Adams',
        1987
    );
    """)
con.close()
fetchone()?

獲取一個(gè)查詢結(jié)果集的下一行,返回一個(gè)單獨(dú)序列,或是在沒有更多可用數(shù)據(jù)時(shí)返回 None。

fetchmany(size=cursor.arraysize)?

獲取下一個(gè)多行查詢結(jié)果集,返回一個(gè)列表。 當(dāng)沒有更多可用行時(shí)將返回一個(gè)空列表。

每次調(diào)用獲取的行數(shù)由 size 形參指定。 如果沒有給出該形參,則由 cursor 的 arraysize 決定要獲取的行數(shù)。 此方法將基于 size 形參值嘗試獲取指定數(shù)量的行。 如果獲取不到指定的行數(shù),則可能返回較少的行。

請(qǐng)注意 size 形參會(huì)涉及到性能方面的考慮。為了獲得優(yōu)化的性能,通常最好是使用 arraysize 屬性。 如果使用 size 形參,則最好在從一個(gè) fetchmany() 調(diào)用到下一個(gè)調(diào)用之間保持相同的值。

fetchall()?

獲取一個(gè)查詢結(jié)果的所有(剩余)行,返回一個(gè)列表。 請(qǐng)注意 cursor 的 arraysize 屬性會(huì)影響此操作的執(zhí)行效率。 當(dāng)沒有可用行時(shí)將返回一個(gè)空列表。

close()?

立即關(guān)閉 cursor(而不是在當(dāng) __del__ 被調(diào)用的時(shí)候)。

從這一時(shí)刻起該 cursor 將不再可用,如果再嘗試用該 cursor 執(zhí)行任何操作將引發(fā) ProgrammingError 異常。

rowcount?

雖然 sqlite3 模塊的 Cursor 類實(shí)現(xiàn)了此屬性,但數(shù)據(jù)庫(kù)引擎本身對(duì)于確定 "受影響行"/"已選擇行" 的支持并不完善。

對(duì)于 executemany() 語(yǔ)句,修改行數(shù)會(huì)被匯總至 rowcount。

根據(jù) Python DB API 規(guī)格描述的要求,rowcount 屬性 "當(dāng)未在 cursor 上執(zhí)行 executeXX() 或者上一次操作的 rowcount 不是由接口確定時(shí)為 -1"。 這包括 SELECT 語(yǔ)句,因?yàn)槲覀儫o(wú)法確定一次查詢將產(chǎn)生的行計(jì)數(shù),而要等獲取了所有行時(shí)才會(huì)知道。。

在 SQLite 的 3.6.5 版之前,如果你執(zhí)行 DELETE FROM table 時(shí)不附帶任何條件,則 rowcount 將被設(shè)為 0。

lastrowid?

這個(gè)只讀屬性會(huì)提供最近修改行的 rowid。 它只在你使用 execute() 方法執(zhí)行 INSERTREPLACE 語(yǔ)句時(shí)會(huì)被設(shè)置。 對(duì)于 INSERTREPLACE 以外的操作或者當(dāng) executemany() 被調(diào)用時(shí),lastrowid 會(huì)被設(shè)為 None

如果 INSERTREPLACE 語(yǔ)句操作失敗則將返回上一次成功操作的 rowid。

在 3.6 版更改: 增加了 REPLACE 語(yǔ)句的支持。

arraysize?

用于控制 fetchmany() 返回行數(shù)的可讀取/寫入屬性。 該屬性的默認(rèn)值為 1,表示每次調(diào)用將獲取單獨(dú)一行。

description?

這個(gè)只讀屬性將提供上一次查詢的列名稱。 為了與 Python DB API 保持兼容,它會(huì)為每個(gè)列返回一個(gè) 7 元組,每個(gè)元組的最后六個(gè)條目均為 None。

對(duì)于沒有任何匹配行的 SELECT 語(yǔ)句同樣會(huì)設(shè)置該屬性。

connection?

這個(gè)只讀屬性將提供 Cursor 對(duì)象所使用的 SQLite 數(shù)據(jù)庫(kù) Connection。 通過調(diào)用 con.cursor() 創(chuàng)建的 Cursor 對(duì)象所包含的 connection 屬性將指向 con:

>>> con = sqlite3.connect(":memory:")
>>> cur = con.cursor()
>>> cur.connection == con
True

行對(duì)象*Row*?

class sqlite3.Row?

一個(gè) Row 實(shí)例,該實(shí)例將作為用于 Connection 對(duì)象的高度優(yōu)化的 row_factory。 它的大部分行為都會(huì)模仿元組的特性。

它支持使用列名稱的映射訪問以及索引、迭代、文本表示、相等檢測(cè)和 len() 等操作。

如果兩個(gè) Row 對(duì)象具有完全相同的列并且其成員均相等,則它們的比較結(jié)果為相等。

keys()?

此方法會(huì)在一次查詢之后立即返回一個(gè)列名稱的列表,它是 Cursor.description 中每個(gè)元組的第一個(gè)成員。

在 3.5 版更改: 添加了對(duì)切片操作的支持。

讓我們假設(shè)我們?nèi)缟厦娴睦铀境跏蓟粋€(gè)表:

conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")
conn.commit()
c.close()

現(xiàn)在我們將 Row 插入:

>>> conn.row_factory = sqlite3.Row
>>> c = conn.cursor()
>>> c.execute('select * from stocks')
<sqlite3.Cursor object at 0x7f4e7dd8fa80>
>>> r = c.fetchone()
>>> type(r)
<class 'sqlite3.Row'>
>>> tuple(r)
('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
>>> len(r)
5
>>> r[2]
'RHAT'
>>> r.keys()
['date', 'trans', 'symbol', 'qty', 'price']
>>> r['qty']
100.0
>>> for member in r:
...     print(member)
...
2006-01-05
BUY
RHAT
100.0
35.14

異常?

exception sqlite3.Warning?

Exception 的一個(gè)子類。

exception sqlite3.Error?

此模塊中其他異常的基類。 它是 Exception 的一個(gè)子類。

exception sqlite3.DatabaseError?

針對(duì)數(shù)據(jù)庫(kù)相關(guān)錯(cuò)誤引發(fā)的異常。

exception sqlite3.IntegrityError?

當(dāng)數(shù)據(jù)庫(kù)的關(guān)系一致性受到影響時(shí)引發(fā)的異常。 例如外鍵檢查失敗等。 它是 DatabaseError 的子類。

exception sqlite3.ProgrammingError?

編程錯(cuò)誤引發(fā)的異常,例如表未找到或已存在,SQL 語(yǔ)句存在語(yǔ)法錯(cuò)誤,指定的形參數(shù)量錯(cuò)誤等。 它是 DatabaseError 的子類。

exception sqlite3.OperationalError?

與數(shù)據(jù)庫(kù)操作相關(guān)而不一定能受程序員掌控的錯(cuò)誤引發(fā)的異常,例如發(fā)生非預(yù)期的連接中斷,數(shù)據(jù)源名稱未找到,事務(wù)無(wú)法被執(zhí)行等。 它是 DatabaseError 的子類。

exception sqlite3.NotSupportedError?

在使用了某個(gè)數(shù)據(jù)庫(kù)不支持的方法或數(shù)據(jù)庫(kù) API 時(shí)引發(fā)的異常,例如在一個(gè)不支持事務(wù)或禁用了事務(wù)的連接上調(diào)用 rollback() 方法等。 它是 DatabaseError 的子類。

SQLite 與 Python 類型?

概述?

SQLite 原生支持如下的類型: NULL,INTEGER,REAL,TEXT,BLOB。

因此可以將以下Python類型發(fā)送到SQLite而不會(huì)出現(xiàn)任何問題:

Python 類型

SQLite 類型

None

NULL

int

INTEGER

float

REAL

str

TEXT

bytes

BLOB

這是SQLite類型默認(rèn)轉(zhuǎn)換為Python類型的方式:

SQLite 類型

Python 類型

NULL

None

INTEGER

int

REAL

float

TEXT

取決于 text_factory , 默認(rèn)為 str

BLOB

bytes

sqlite3 模塊的類型系統(tǒng)可通過兩種方式來(lái)擴(kuò)展:你可以通過對(duì)象適配將額外的 Python 類型保存在 SQLite 數(shù)據(jù)庫(kù)中,你也可以讓 sqlite3 模塊通過轉(zhuǎn)換器將 SQLite 類型轉(zhuǎn)換為不同的 Python 類型。

使用適配器將額外的 Python 類型保存在 SQLite 數(shù)據(jù)庫(kù)中。?

如上文所述,SQLite 只包含對(duì)有限類型集的原生支持。 要讓 SQLite 能使用其他 Python 類型,你必須將它們 適配 至 sqlite3 模塊所支持的 SQLite 類型中的一種:NoneType, int, float, str, bytes。

有兩種方式能讓 sqlite3 模塊將某個(gè)定制的 Python 類型適配為受支持的類型。

讓對(duì)象自行調(diào)整?

如果自己編寫類,這是一種很好的方法。假設(shè)有這樣的類::

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

現(xiàn)在你想將這種點(diǎn)對(duì)象保存在一個(gè) SQLite 列中。 首先你必須選擇一種受支持的類型用來(lái)表示點(diǎn)對(duì)象。 讓我們就用 str 并使用一個(gè)分號(hào)來(lái)分隔坐標(biāo)值。 然后你需要給你的類加一個(gè)方法 __conform__(self, protocol),它必須返回轉(zhuǎn)換后的值。 形參 protocol 將為 PrepareProtocol。

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return "%f;%f" % (self.x, self.y)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])

con.close()

注冊(cè)可調(diào)用的適配器?

另一種可能的做法是創(chuàng)建一個(gè)將該類型轉(zhuǎn)換為字符串表示的函數(shù)并使用 register_adapter() 注冊(cè)該函數(shù)。

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

def adapt_point(point):
    return "%f;%f" % (point.x, point.y)

sqlite3.register_adapter(Point, adapt_point)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])

con.close()

sqlite3 模塊有兩個(gè)適配器可用于 Python 的內(nèi)置 datetime.datedatetime.datetime 類型。 現(xiàn)在假設(shè)我們想要存儲(chǔ) datetime.datetime 對(duì)象,但不是表示為 ISO 格式,而是表示為 Unix 時(shí)間戳。

import sqlite3
import datetime
import time

def adapt_datetime(ts):
    return time.mktime(ts.timetuple())

sqlite3.register_adapter(datetime.datetime, adapt_datetime)

con = sqlite3.connect(":memory:")
cur = con.cursor()

now = datetime.datetime.now()
cur.execute("select ?", (now,))
print(cur.fetchone()[0])

con.close()

將SQLite 值轉(zhuǎn)換為自定義Python 類型?

編寫適配器讓你可以將定制的 Python 類型發(fā)送給 SQLite。 但要令它真正有用,我們需要實(shí)現(xiàn)從 Python 到 SQLite 再回到 Python 的雙向轉(zhuǎn)換。

輸入轉(zhuǎn)換器。

讓我們回到 Point 類。 我們以字符串形式在 SQLite 中存儲(chǔ)了 x 和 y 坐標(biāo)值。

首先,我們將定義一個(gè)轉(zhuǎn)換器函數(shù),它接受這樣的字符串作為形參并根據(jù)該參數(shù)構(gòu)造一個(gè) Point 對(duì)象。

注解

轉(zhuǎn)換器函數(shù)在調(diào)用時(shí) 總是 會(huì)附帶一個(gè) bytes 對(duì)象,無(wú)論你將何種數(shù)據(jù)類型的值發(fā)給 SQLite。

def convert_point(s):
    x, y = map(float, s.split(b";"))
    return Point(x, y)

現(xiàn)在你需要讓 sqlite3 模塊知道你從數(shù)據(jù)庫(kù)中選取的其實(shí)是一個(gè)點(diǎn)對(duì)象。 有兩種方式都可以做到這件事:

  • 隱式的聲明類型

  • 顯式的通過列名

這兩種方式會(huì)在 模塊函數(shù)和常量 一節(jié)中描述,相應(yīng)條目為 PARSE_DECLTYPESPARSE_COLNAMES 常量。

下面的示例說明了這兩種方法。

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __repr__(self):
        return "(%f;%f)" % (self.x, self.y)

def adapt_point(point):
    return ("%f;%f" % (point.x, point.y)).encode('ascii')

def convert_point(s):
    x, y = list(map(float, s.split(b";")))
    return Point(x, y)

# Register the adapter
sqlite3.register_adapter(Point, adapt_point)

# Register the converter
sqlite3.register_converter("point", convert_point)

p = Point(4.0, -3.2)

#########################
# 1) Using declared types
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table test(p point)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute("select p from test")
print("with declared types:", cur.fetchone()[0])
cur.close()
con.close()

#######################
# 1) Using column names
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(p)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute('select p as "p [point]" from test')
print("with column names:", cur.fetchone()[0])
cur.close()
con.close()

默認(rèn)適配器和轉(zhuǎn)換器?

對(duì)于 datetime 模塊中的 date 和 datetime 類型已提供了默認(rèn)的適配器。 它們將會(huì)以 ISO 日期/ISO 時(shí)間戳的形式發(fā)給 SQLite。

默認(rèn)轉(zhuǎn)換器使用的注冊(cè)名稱是針對(duì) datetime.date 的 "date" 和針對(duì) datetime.datetime 的 "timestamp"。

通過這種方式,你可以在大多數(shù)情況下使用 Python 的 date/timestamp 對(duì)象而無(wú)須任何額外處理。 適配器的格式還與實(shí)驗(yàn)性的 SQLite date/time 函數(shù)兼容。

下面的示例演示了這一點(diǎn)。

import sqlite3
import datetime

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(d date, ts timestamp)")

today = datetime.date.today()
now = datetime.datetime.now()

cur.execute("insert into test(d, ts) values (?, ?)", (today, now))
cur.execute("select d, ts from test")
row = cur.fetchone()
print(today, "=>", row[0], type(row[0]))
print(now, "=>", row[1], type(row[1]))

cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')
row = cur.fetchone()
print("current_date", row[0], type(row[0]))
print("current_timestamp", row[1], type(row[1]))

con.close()

如果存儲(chǔ)在 SQLite 中的時(shí)間戳的小數(shù)位多于 6 個(gè)數(shù)字,則時(shí)間戳轉(zhuǎn)換器會(huì)將該值截?cái)嘀廖⒚刖取?/p>

控制事務(wù)?

底層的 sqlite3 庫(kù)默認(rèn)會(huì)以 autocommit 模式運(yùn)行,但 Python 的 sqlite3 模塊默認(rèn)則不使用此模式。

autocommit 模式意味著修改數(shù)據(jù)庫(kù)的操作會(huì)立即生效。 BEGINSAVEPOINT 語(yǔ)句會(huì)禁用 autocommit 模式,而用于結(jié)束外層事務(wù)的 COMMIT, ROLLBACKRELEASE 則會(huì)恢復(fù) autocommit 模式。

Python 的 sqlite3 模塊默認(rèn)會(huì)在數(shù)據(jù)修改語(yǔ)言 (DML) 類語(yǔ)句 (即 INSERT/UPDATE/DELETE/REPLACE) 之前隱式地執(zhí)行一條 BEGIN 語(yǔ)句。

你可以控制 sqlite3 隱式執(zhí)行的 BEGIN 語(yǔ)句的種類,具體做法是通過將 isolation_level 形參傳給 connect() 調(diào)用,或者通過指定連接的 isolation_level 屬性。 如果你沒有指定 isolation_level,將使用基本的 BEGIN,它等價(jià)于指定 DEFERRED。 其他可能的值為 IMMEDIATEEXCLUSIVE

你可以禁用 sqlite3 模塊的隱式事務(wù)管理,具體做法是將 isolation_level 設(shè)為 None。 這將使得下層的 sqlite3 庫(kù)采用 autocommit 模式。 隨后你可以通過在代碼中顯式地使用 BEGIN, ROLLBACK, SAVEPOINTRELEASE 語(yǔ)句來(lái)完全控制事務(wù)狀態(tài)。

在 3.6 版更改: 以前 sqlite3 會(huì)在 DDL 語(yǔ)句之前隱式地提交未完成事務(wù)。 現(xiàn)在則不會(huì)再這樣做。

有效使用 sqlite3?

使用快捷方式?

使用 Connection 對(duì)象的非標(biāo)準(zhǔn) execute(), executemany()executescript() 方法,可以更簡(jiǎn)潔地編寫代碼,因?yàn)椴槐仫@式創(chuàng)建(通常是多余的) Cursor 對(duì)象。相反, Cursor 對(duì)象是隱式創(chuàng)建的,這些快捷方法返回游標(biāo)對(duì)象。這樣,只需對(duì) Connection 對(duì)象調(diào)用一次,就能直接執(zhí)行 SELECT 語(yǔ)句并遍歷對(duì)象。

import sqlite3

persons = [
    ("Hugo", "Boss"),
    ("Calvin", "Klein")
    ]

con = sqlite3.connect(":memory:")

# Create the table
con.execute("create table person(firstname, lastname)")

# Fill the table
con.executemany("insert into person(firstname, lastname) values (?, ?)", persons)

# Print the table contents
for row in con.execute("select firstname, lastname from person"):
    print(row)

print("I just deleted", con.execute("delete from person").rowcount, "rows")

# close is not a shortcut method and it's not called automatically,
# so the connection object should be closed manually
con.close()

通過名稱而不是索引訪問索引?

sqlite3 模塊的一個(gè)有用功能是內(nèi)置的 sqlite3.Row 類,它被設(shè)計(jì)用作行對(duì)象的工廠。

該類的行裝飾器可以用索引(如元組)和不區(qū)分大小寫的名稱訪問:

import sqlite3

con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row

cur = con.cursor()
cur.execute("select 'John' as name, 42 as age")
for row in cur:
    assert row[0] == row["name"]
    assert row["name"] == row["nAmE"]
    assert row[1] == row["age"]
    assert row[1] == row["AgE"]

con.close()

使用連接作為上下文管理器?

連接對(duì)象可以用來(lái)作為上下文管理器,它可以自動(dòng)提交或者回滾事務(wù)。如果出現(xiàn)異常,事務(wù)會(huì)被回滾;否則,事務(wù)會(huì)被提交。

import sqlite3

con = sqlite3.connect(":memory:")
con.execute("create table person (id integer primary key, firstname varchar unique)")

# Successful, con.commit() is called automatically afterwards
with con:
    con.execute("insert into person(firstname) values (?)", ("Joe",))

# con.rollback() is called after the with block finishes with an exception, the
# exception is still raised and must be caught
try:
    with con:
        con.execute("insert into person(firstname) values (?)", ("Joe",))
except sqlite3.IntegrityError:
    print("couldn't add Joe twice")

# Connection object used as context manager only commits or rollbacks transactions,
# so the connection object should be closed manually
con.close()

常見問題?

多線程?

較老版本的 SQLite 在共享線程之間存在連接問題。這就是Python模塊不允許線程之間共享連接和游標(biāo)的原因。如果仍然嘗試這樣做,則在運(yùn)行時(shí)會(huì)出現(xiàn)異常。

唯一的例外是調(diào)用 interrupt() 方法,該方法僅在從其他線程進(jìn)行調(diào)用時(shí)才有意義。

備注

1(1,2)

sqlite3 模塊默認(rèn)沒有構(gòu)建可加載擴(kuò)展支持,因?yàn)橛幸恍┢脚_(tái)帶有不支持這個(gè)特性的 SQLite 庫(kù)(特別是 Mac OS X)。要獲得可加載擴(kuò)展的支持,那么在編譯配置的時(shí)候必須指定 --enable-loadable-sqlite-extensions 選項(xiàng)。