sqlite3 — 適用於 SQLite 資料庫的 DB-API 2.0 介面

原始碼: Lib/sqlite3/

SQLite 是一個 C 庫,它提供了一個輕量級的基於磁碟的資料庫,不需要單獨的伺服器程序,並允許使用 SQL 查詢語言的非標準變體來訪問資料庫。一些應用程式可以使用 SQLite 進行內部資料儲存。還可以使用 SQLite 構建應用程式原型,然後將程式碼移植到更大的資料庫,例如 PostgreSQL 或 Oracle。

sqlite3 模組由 Gerhard Häring 編寫。它提供了一個符合 PEP 249 描述的 DB-API 2.0 規範的 SQL 介面,並且需要 SQLite 3.15.2 或更新版本。

本文件包含四個主要部分

  • 教程 教授如何使用 sqlite3 模組。

  • 參考 描述了此模組定義的類和函式。

  • 操作指南 詳細介紹瞭如何處理特定任務。

  • 說明 提供了有關事務控制的深入背景資訊。

參見

https://www.sqlite.org

SQLite 網頁;文件描述了所支援 SQL 方言的語法和可用資料型別。

https://w3schools.tw/sql/

用於學習 SQL 語法的教程、參考和示例。

PEP 249 - 資料庫 API 規範 2.0

由 Marc-André Lemburg 編寫的 PEP。

教程

在本教程中,您將使用基本的 sqlite3 功能建立一個 Monty Python 電影資料庫。它假定您對資料庫概念有基本瞭解,包括 遊標事務

首先,我們需要建立一個新資料庫並開啟一個數據庫連線,以允許 sqlite3 對其進行操作。呼叫 sqlite3.connect() 在當前工作目錄中建立與資料庫 tutorial.db 的連線,如果它不存在則隱式建立它

import sqlite3
con = sqlite3.connect("tutorial.db")

返回的 Connection 物件 con 表示與磁碟資料庫的連線。

為了執行 SQL 語句並從 SQL 查詢中獲取結果,我們需要使用資料庫遊標。呼叫 con.cursor() 來建立 Cursor

cur = con.cursor()

現在我們已經有了資料庫連線和遊標,我們可以建立一個數據庫表 movie,其中包含標題、釋出年份和評分的列。為簡單起見,我們可以在表宣告中只使用列名——由於 SQLite 的 靈活型別 功能,指定資料型別是可選的。透過呼叫 cur.execute(...) 執行 CREATE TABLE 語句

cur.execute("CREATE TABLE movie(title, year, score)")

我們可以透過查詢 SQLite 內建的 sqlite_master 表來驗證新表是否已建立,該表現在應該包含 movie 表定義的條目(有關詳細資訊,請參閱 Schema Table)。透過呼叫 cur.execute(...) 執行該查詢,將結果分配給 res,然後呼叫 res.fetchone() 來獲取結果行

>>> res = cur.execute("SELECT name FROM sqlite_master")
>>> res.fetchone()
('movie',)

我們可以看到表已經建立,因為查詢返回一個包含表名的 元組。如果我們查詢 sqlite_master 以查詢不存在的表 spamres.fetchone() 將返回 None

>>> res = cur.execute("SELECT name FROM sqlite_master WHERE name='spam'")
>>> res.fetchone() is None
True

現在,透過執行 INSERT 語句,再次透過呼叫 cur.execute(...),新增作為 SQL 字面量提供的兩行資料

cur.execute("""
    INSERT INTO movie VALUES
        ('Monty Python and the Holy Grail', 1975, 8.2),
        ('And Now for Something Completely Different', 1971, 7.5)
""")

INSERT 語句隱式地開啟一個事務,該事務需要在更改儲存到資料庫之前提交(有關詳細資訊,請參閱 事務控制)。在連線物件上呼叫 con.commit() 來提交事務

con.commit()

我們可以透過執行 SELECT 查詢來驗證資料是否已正確插入。使用現在熟悉的 cur.execute(...) 將結果分配給 res,然後呼叫 res.fetchall() 返回所有結果行

>>> res = cur.execute("SELECT score FROM movie")
>>> res.fetchall()
[(8.2,), (7.5,)]

結果是一個包含兩個 tuplelist,每行一個,每個 tuple 包含該行的 score 值。

現在,透過呼叫 cur.executemany(...) 插入另外三行

data = [
    ("Monty Python Live at the Hollywood Bowl", 1982, 7.9),
    ("Monty Python's The Meaning of Life", 1983, 7.5),
    ("Monty Python's Life of Brian", 1979, 8.0),
]
cur.executemany("INSERT INTO movie VALUES(?, ?, ?)", data)
con.commit()  # Remember to commit the transaction after executing INSERT.

注意,? 佔位符用於將 data 繫結到查詢。始終使用佔位符而不是 字串格式化 將 Python 值繫結到 SQL 語句,以避免 SQL 注入攻擊(有關詳細資訊,請參閱 如何使用佔位符繫結 SQL 查詢中的值)。

我們可以透過執行 SELECT 查詢來驗證新行是否已插入,這次迭代查詢結果

>>> for row in cur.execute("SELECT year, title FROM movie ORDER BY year"):
...     print(row)
(1971, 'And Now for Something Completely Different')
(1975, 'Monty Python and the Holy Grail')
(1979, "Monty Python's Life of Brian")
(1982, 'Monty Python Live at the Hollywood Bowl')
(1983, "Monty Python's The Meaning of Life")

每行是一個包含兩個專案的 元組 (year, title),與查詢中選擇的列匹配。

最後,透過呼叫 con.close() 關閉現有連線,開啟新連線,建立新遊標,然後查詢資料庫,驗證資料庫是否已寫入磁碟

>>> con.close()
>>> new_con = sqlite3.connect("tutorial.db")
>>> new_cur = new_con.cursor()
>>> res = new_cur.execute("SELECT title, year FROM movie ORDER BY score DESC")
>>> title, year = res.fetchone()
>>> print(f'The highest scoring Monty Python movie is {title!r}, released in {year}')
The highest scoring Monty Python movie is 'Monty Python and the Holy Grail', released in 1975
>>> new_con.close()

您現在已經使用 sqlite3 模組建立了一個 SQLite 資料庫,並以多種方式插入資料並從中檢索值。

參考

模組函式

sqlite3.connect(database, timeout=5.0, detect_types=0, isolation_level='DEFERRED', check_same_thread=True, factory=sqlite3.Connection, cached_statements=128, uri=False, *, autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL)

開啟與 SQLite 資料庫的連線。

引數:
返回型別:

Connection

引發一個 審計事件 sqlite3.connect,引數為 database

引發一個 審計事件 sqlite3.connect/handle,引數為 connection_handle

3.4 版本中已更改: 添加了 uri 引數。

3.7 版本中已更改: database 現在也可以是 類路徑物件,而不僅僅是字串。

3.10 版本中已更改: 添加了 sqlite3.connect/handle 審計事件。

3.12 版本中已更改: 添加了 autocommit 引數。

3.13 版本中已更改: 引數 timeout, detect_types, isolation_level, check_same_thread, factory, cached_statementsuri 的位置引數用法已棄用。它們將在 Python 3.15 中成為僅限關鍵字的引數。

sqlite3.complete_statement(statement)

如果字串 statement 似乎包含一個或多個完整的 SQL 語句,則返回 True。除了檢查沒有未閉合的字串字面量以及語句以分號終止之外,不執行任何句法驗證或解析。

例如:

>>> sqlite3.complete_statement("SELECT foo FROM bar;")
True
>>> sqlite3.complete_statement("SELECT foo")
False

此函式在命令列輸入期間可能很有用,用於確定輸入的文字是否似乎構成了一個完整的 SQL 語句,或者在呼叫 execute() 之前是否需要額外輸入。

有關實際用法,請參閱 Lib/sqlite3/__main__.py 中的 runsource()

sqlite3.enable_callback_tracebacks(flag, /)

啟用或停用回調回溯。預設情況下,您不會在使用者定義函式、聚合、轉換器、授權器回撥等中獲得任何回溯。如果您想除錯它們,可以呼叫此函式並將 *flag* 設定為 True。之後,您將在 sys.stderr 上獲取回撥的回溯。使用 False 再次停用該功能。

備註

使用者定義函式回撥中的錯誤將作為不可引發的異常記錄。使用 unraisable hook handler 來檢查失敗的回撥。

sqlite3.register_adapter(type, adapter, /)

註冊一個 *adapter* 可呼叫物件,用於將 Python 型別 *type* 適配為 SQLite 型別。介面卡以 *type* 型別的 Python 物件作為其唯一引數呼叫,並且必須返回 SQLite 原生理解的型別 的值。

sqlite3.register_converter(typename, converter, /)

註冊 *converter* 可呼叫物件,用於將 *typename* 型別的 SQLite 物件轉換為特定型別的 Python 物件。轉換器將為 *typename* 型別的所有 SQLite 值呼叫;它將接收一個 bytes 物件,並應返回所需 Python 型別的物件。有關型別檢測工作原理的資訊,請查閱 connect() 的引數 *detect_types*。

注意:*typename* 和查詢中型別名稱的匹配不區分大小寫。

模組常量

sqlite3.LEGACY_TRANSACTION_CONTROL

autocommit 設定為此常量以選擇舊式(Python 3.12 之前)事務控制行為。有關更多資訊,請參閱 透過 isolation_level 屬性進行事務控制

sqlite3.PARSE_DECLTYPES

將此標誌值傳遞給 connect() 的 *detect_types* 引數,以使用每列的宣告型別查詢轉換函式。型別在建立資料庫表時宣告。sqlite3 將使用宣告型別中的第一個單詞作為轉換器字典鍵來查詢轉換函式。例如

CREATE TABLE test(
   i integer primary key,  ! will look up a converter named "integer"
   p point,                ! will look up a converter named "point"
   n number(10)            ! will look up a converter named "number"
 )

此標誌可以與 PARSE_COLNAMES 使用 |(按位或)運算子結合使用。

備註

生成欄位(例如 MAX(p))作為 str 返回。使用 PARSE_COLNAMES 為此類查詢強制執行型別。

sqlite3.PARSE_COLNAMES

將此標誌值傳遞給 connect() 的 *detect_types* 引數,以使用從查詢列名解析出的型別名作為轉換器字典鍵來查詢轉換函式。查詢列名必須用雙引號 (") 包裹,型別名必須用方括號 ([]) 包裹。

SELECT MAX(p) as "p [point]" FROM test;  ! will look up converter "point"

此標誌可以與 PARSE_DECLTYPES 使用 |(按位或)運算子結合使用。

sqlite3.SQLITE_OK
sqlite3.SQLITE_DENY
sqlite3.SQLITE_IGNORE

應由傳遞給 Connection.set_authorizer() 的 *authorizer_callback* 可呼叫物件 返回的標誌,以指示是否

  • 允許訪問 (SQLITE_OK),

  • SQL 語句應因錯誤而中止 (SQLITE_DENY)

  • 該列應被視為 NULL 值 (SQLITE_IGNORE)

sqlite3.apilevel

表示支援的 DB-API 級別的字串常量。DB-API 要求。硬編碼為 "2.0"

sqlite3.paramstyle

表示 sqlite3 模組期望的引數標記格式型別的字串常量。DB-API 要求。硬編碼為 "qmark"

備註

還支援 named DB-API 引數樣式。

sqlite3.sqlite_version

執行時 SQLite 庫的版本號,以 字串 形式表示。

sqlite3.sqlite_version_info

執行時 SQLite 庫的版本號,以 整數 元組 形式表示。

sqlite3.threadsafety

DB-API 2.0 要求的整數常量,表示 sqlite3 模組支援的執行緒安全級別。此屬性根據底層 SQLite 庫編譯時使用的預設 執行緒模式 設定。SQLite 執行緒模式有

  1. 單執行緒:在此模式下,所有互斥體都被停用,SQLite 在一次只能有一個執行緒中使用是不安全的。

  2. 多執行緒:在此模式下,只要沒有單個數據庫連線同時在兩個或更多執行緒中使用,SQLite 就可以被多個執行緒安全地使用。

  3. 序列化:在序列化模式下,SQLite 可以被多個執行緒安全地使用,沒有任何限制。

SQLite 執行緒模式到 DB-API 2.0 執行緒安全級別的對映如下

SQLite 執行緒模式

threadsafety

SQLITE_THREADSAFE

DB-API 2.0 含義

單執行緒

0

0

執行緒不能共享模組

多執行緒

1

2

執行緒可以共享模組,但不能共享連線

序列化

3

1

執行緒可以共享模組、連線和遊標

3.11 版本中已更改: 動態設定 threadsafety 而不是硬編碼為 1

sqlite3.SQLITE_DBCONFIG_DEFENSIVE
sqlite3.SQLITE_DBCONFIG_DQS_DDL
sqlite3.SQLITE_DBCONFIG_DQS_DML
sqlite3.SQLITE_DBCONFIG_ENABLE_FKEY
sqlite3.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
sqlite3.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
sqlite3.SQLITE_DBCONFIG_ENABLE_QPSG
sqlite3.SQLITE_DBCONFIG_ENABLE_TRIGGER
sqlite3.SQLITE_DBCONFIG_ENABLE_VIEW
sqlite3.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
sqlite3.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
sqlite3.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
sqlite3.SQLITE_DBCONFIG_RESET_DATABASE
sqlite3.SQLITE_DBCONFIG_TRIGGER_EQP
sqlite3.SQLITE_DBCONFIG_TRUSTED_SCHEMA
sqlite3.SQLITE_DBCONFIG_WRITABLE_SCHEMA

這些常量用於 Connection.setconfig()getconfig() 方法。

這些常量的可用性取決於 Python 編譯時使用的 SQLite 版本。

3.12 新版功能.

參見

https://www.sqlite.org/c3ref/c_dbconfig_defensive.html

SQLite 文件:資料庫連線配置選項

自 3.12 版本棄用,在 3.14 版本中刪除: versionversion_info 常量。

連線物件

class sqlite3.Connection

每個開啟的 SQLite 資料庫都由一個 Connection 物件表示,該物件使用 sqlite3.connect() 建立。它們的主要目的是建立 Cursor 物件和 事務控制

3.13 版本中已更改: 如果在 Connection 物件被刪除之前未呼叫 close(),則會發出 ResourceWarning

SQLite 資料庫連線具有以下屬性和方法

cursor(factory=Cursor)

建立並返回一個 Cursor 物件。遊標方法接受一個可選引數 *factory*。如果提供,它必須是一個 可呼叫物件,返回 Cursor 或其子類的例項。

blobopen(table, column, rowid, /, *, readonly=False, name='main')

開啟一個 Blob 控制代碼以操作現有 BLOB

引數:
  • table (字串) – Blob 所在的表的名稱。

  • column (字串) – Blob 所在的列的名稱。

  • rowid (整數) – Blob 所在的行 ID。

  • readonly (布林值) – 如果 blob 應以無寫入許可權開啟,則設定為 True。預設為 False

  • name (字串) – Blob 所在的資料庫名稱。預設為 "main"

引發:

OperationalError – 當嘗試在 WITHOUT ROWID 表中開啟 blob 時。

返回型別:

Blob

備註

Blob 大小不能使用 Blob 類更改。使用 SQL 函式 zeroblob 建立具有固定大小的 blob。

在 3.11 版本中新增。

commit()

將所有待處理的事務提交到資料庫。如果 autocommitTrue,或者沒有開啟的事務,則此方法不執行任何操作。如果 autocommitFalse,並且此方法提交了待處理的事務,則會隱式開啟一個新事務。

rollback()

回滾到任何待處理事務的開始。如果 autocommitTrue,或者沒有開啟的事務,則此方法不執行任何操作。如果 autocommitFalse,並且此方法回滾了待處理的事務,則會隱式開啟一個新事務。

close()

關閉資料庫連線。如果 autocommitFalse,則任何待處理的事務都將被隱式回滾。如果 autocommitTrueLEGACY_TRANSACTION_CONTROL,則不執行隱式事務控制。請確保在關閉之前 commit() 以避免丟失待處理的更改。

execute(sql, parameters=(), /)

建立一個新的 Cursor 物件,並使用給定的 *sql* 和 *parameters* 在其上呼叫 execute()。返回新的遊標物件。

executemany(sql, parameters, /)

建立一個新的 Cursor 物件,並使用給定的 *sql* 和 *parameters* 在其上呼叫 executemany()。返回新的遊標物件。

executescript(sql_script, /)

建立一個新的 Cursor 物件,並使用給定的 *sql_script* 在其上呼叫 executescript()。返回新的遊標物件。

create_function(name, narg, func, *, deterministic=False)

建立或刪除使用者定義的 SQL 函式。

引數:
  • name (字串) – SQL 函式的名稱。

  • narg (整數) – SQL 函式可以接受的引數數量。如果為 -1,則它可以接受任意數量的引數。

  • func (回撥函式 | None) – 當 SQL 函式被呼叫時呼叫的 可呼叫物件。可呼叫物件必須返回 SQLite 原生支援的型別。設定為 None 以刪除現有 SQL 函式。

  • deterministic (布林值) – 如果為 True,則建立的 SQL 函式被標記為 確定性的,這允許 SQLite 執行額外的最佳化。

3.8 版本中已更改: 添加了 deterministic 引數。

示例

>>> import hashlib
>>> def md5sum(t):
...     return hashlib.md5(t).hexdigest()
>>> con = sqlite3.connect(":memory:")
>>> con.create_function("md5", 1, md5sum)
>>> for row in con.execute("SELECT md5(?)", (b"foo",)):
...     print(row)
('acbd18db4cc2f85cedef654fccc4a4d8',)
>>> con.close()

3.13 版本中已更改: 將 *name*、*narg* 和 *func* 作為關鍵字引數傳遞已棄用。這些引數將在 Python 3.15 中成為僅位置引數。

create_aggregate(name, n_arg, aggregate_class)

建立或刪除使用者定義的 SQL 聚合函式。

引數:
  • name (字串) – SQL 聚合函式的名稱。

  • n_arg (整數) – SQL 聚合函式可以接受的引數數量。如果為 -1,則它可以接受任意數量的引數。

  • aggregate_class ( | None) –

    一個類必須實現以下方法

    step() 方法必須接受的引數數量由 *n_arg* 控制。

    設定為 None 以刪除現有 SQL 聚合函式。

示例

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.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()

3.13 版本中已更改: 將 *name*、*n_arg* 和 *aggregate_class* 作為關鍵字引數傳遞已棄用。這些引數將在 Python 3.15 中成為僅位置引數。

create_window_function(name, num_params, aggregate_class, /)

建立或刪除使用者定義的聚合視窗函式。

引數:
  • name (字串) – 要建立或刪除的 SQL 聚合視窗函式的名稱。

  • num_params (整數) – SQL 聚合視窗函式可以接受的引數數量。如果為 -1,則它可以接受任意數量的引數。

  • aggregate_class ( | None) –

    一個類必須實現以下方法

    • step(): 向當前視窗新增一行。

    • value(): 返回聚合的當前值。

    • inverse(): 從當前視窗中刪除一行。

    • finalize(): 以 SQLite 原生支援的型別 返回聚合的最終結果。

    step()value() 方法必須接受的引數數量由 *num_params* 控制。

    設定為 None 以刪除現有 SQL 聚合視窗函式。

引發:

NotSupportedError – 如果與早於 3.25.0 的 SQLite 版本一起使用,該版本不支援聚合視窗函式。

在 3.11 版本中新增。

示例

# Example taken from https://www.sqlite.org/windowfunctions.html#udfwinfunc
class WindowSumInt:
    def __init__(self):
        self.count = 0

    def step(self, value):
        """Add a row to the current window."""
        self.count += value

    def value(self):
        """Return the current value of the aggregate."""
        return self.count

    def inverse(self, value):
        """Remove a row from the current window."""
        self.count -= value

    def finalize(self):
        """Return the final value of the aggregate.

        Any clean-up actions should be placed here.
        """
        return self.count


con = sqlite3.connect(":memory:")
cur = con.execute("CREATE TABLE test(x, y)")
values = [
    ("a", 4),
    ("b", 5),
    ("c", 3),
    ("d", 8),
    ("e", 1),
]
cur.executemany("INSERT INTO test VALUES(?, ?)", values)
con.create_window_function("sumint", 1, WindowSumInt)
cur.execute("""
    SELECT x, sumint(y) OVER (
        ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
    ) AS sum_y
    FROM test ORDER BY x
""")
print(cur.fetchall())
con.close()
create_collation(name, callable, /)

使用排序函式 *callable* 建立名為 *name* 的排序規則。*callable* 將接收兩個 字串 引數,並且應返回一個 整數

  • 如果第一個排序高於第二個,則為 1

  • 如果第一個排序低於第二個,則為 -1

  • 如果它們排序相等,則為 0

以下示例顯示了一個反向排序的排序規則

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.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()

透過將 *callable* 設定為 None 來刪除排序函式。

3.11 版本中已更改: 排序規則名稱可以包含任何 Unicode 字元。以前,只允許 ASCII 字元。

interrupt()

從不同的執行緒呼叫此方法以中止可能正在連線上執行的任何查詢。中止的查詢將引發 OperationalError

set_authorizer(authorizer_callback)

註冊 可呼叫物件 *authorizer_callback*,用於在每次嘗試訪問資料庫中表的列時呼叫。回撥應返回 SQLITE_OKSQLITE_DENYSQLITE_IGNORE 之一,以指示底層 SQLite 庫應如何處理對列的訪問。

回撥的第一個引數表示要授權的操作型別。第二個和第三個引數將是引數或 None,具體取決於第一個引數。第四個引數是資料庫的名稱("main"、"temp" 等)(如果適用)。第五個引數是負責訪問嘗試的最內層觸發器或檢視的名稱,如果此訪問嘗試直接來自輸入的 SQL 程式碼,則為 None

請查閱 SQLite 文件,瞭解第一個引數的可能值以及第二個和第三個引數的含義,具體取決於第一個引數。所有必要的常量都可以在 sqlite3 模組中找到。

傳遞 None 作為 *authorizer_callback* 將停用授權器。

3.11 版本中已更改: 添加了使用 None 停用授權器的支援。

3.13 版本中已更改: 將 *authorizer_callback* 作為關鍵字引數傳遞已棄用。該引數將在 Python 3.15 中成為僅位置引數。

set_progress_handler(progress_handler, n)

註冊 可呼叫物件 *progress_handler*,以便每 *n* 條 SQLite 虛擬機器指令都會呼叫它。這對於在長時間執行的操作期間從 SQLite 接收呼叫很有用,例如更新 GUI。

如果您想清除任何以前安裝的進度處理程式,請將 *progress_handler* 設定為 None 呼叫此方法。

從處理程式函式返回非零值將終止當前正在執行的查詢,並導致它引發 DatabaseError 異常。

3.13 版本中已更改: 將 *progress_handler* 作為關鍵字引數傳遞已棄用。該引數將在 Python 3.15 中成為僅位置引數。

set_trace_callback(trace_callback)

註冊 可呼叫物件 *trace_callback*,以便為 SQLite 後端實際執行的每個 SQL 語句呼叫它。

傳遞給回撥的唯一引數是正在執行的語句(作為 str)。回撥的返回值將被忽略。請注意,後端不僅執行傳遞給 Cursor.execute() 方法的語句。其他來源包括 sqlite3 模組的 事務管理 以及當前資料庫中定義的觸發器的執行。

None 作為 *trace_callback* 傳遞將停用跟蹤回撥。

備註

在跟蹤回撥中引發的異常不會傳播。作為開發和除錯輔助,請使用 enable_callback_tracebacks() 來啟用列印跟蹤回撥中引發的異常的回溯。

在 3.3 版本加入。

3.13 版本中已更改: 將 *trace_callback* 作為關鍵字引數傳遞已棄用。該引數將在 Python 3.15 中成為僅位置引數。

enable_load_extension(enabled, /)

如果 *enabled* 為 True,則允許 SQLite 引擎從共享庫載入 SQLite 擴充套件;否則,禁止載入 SQLite 擴充套件。SQLite 擴充套件可以定義新函式、聚合或全新的虛擬表實現。一個著名的擴充套件是隨 SQLite 分發的全文搜尋擴充套件。

備註

sqlite3 模組預設不構建為支援可載入擴充套件,因為某些平臺(特別是 macOS)的 SQLite 庫在編譯時未包含此功能。要獲得可載入擴充套件支援,您必須將 --enable-loadable-sqlite-extensions 選項傳遞給 configure

引發一個 審計事件 sqlite3.enable_load_extension,引數為 connectionenabled

在 3.2 版本加入。

3.10 版本中已更改: 添加了 sqlite3.enable_load_extension 審計事件。

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)
load_extension(path, /, *, entrypoint=None)

從共享庫載入 SQLite 擴充套件。在呼叫此方法之前,使用 enable_load_extension() 啟用擴充套件載入。

引數:
  • path (字串) – SQLite 擴充套件的路徑。

  • entrypoint (字串 | None) – 入口點名稱。如果為 None(預設值),SQLite 將自己生成一個入口點名稱;有關詳細資訊,請參閱 SQLite 文件 載入擴充套件

引發一個 審計事件 sqlite3.load_extension,引數為 connectionpath

在 3.2 版本加入。

3.10 版本中已更改: 添加了 sqlite3.load_extension 審計事件。

3.12 版本中已更改: 添加了 *entrypoint* 引數。

iterdump(*, filter=None)

返回一個 迭代器,用於將資料庫轉儲為 SQL 原始碼。在儲存記憶體資料庫以便以後恢復時很有用。類似於 sqlite3 shell 中的 .dump 命令。

引數:

filter (字串 | None) – 用於轉儲資料庫物件的可選 LIKE 模式,例如 prefix_%。如果為 None(預設值),則將包含所有資料庫物件。

示例

# Convert file example.db to SQL dump file dump.sql
con = sqlite3.connect('example.db')
with open('dump.sql', 'w') as f:
    for line in con.iterdump():
        f.write('%s\n' % line)
con.close()

3.13 版本中已更改: 添加了 *filter* 引數。

backup(target, *, pages=-1, progress=None, name='main', sleep=0.250)

建立 SQLite 資料庫的備份。

即使資料庫被其他客戶端或同一連線同時訪問,也有效。

引數:
  • target (Connection) – 用於儲存備份的資料庫連線。

  • pages (整數) – 每次複製的頁數。如果等於或小於 0,則整個資料庫將一次性複製。預設為 -1

  • progress (回撥函式 | None) – 如果設定為 可呼叫物件,則在每次備份迭代時呼叫它,並帶三個整數引數:上次迭代的 *status*、仍要複製的 *remaining* 頁數和 *total* 頁數。預設為 None

  • name (字串) – 要備份的資料庫名稱。可以是 "main"(預設)表示主資料庫,"temp" 表示臨時資料庫,或使用 ATTACH DATABASE SQL 語句附加的自定義資料庫名稱。

  • sleep (浮點數) – 在連續嘗試備份剩餘頁面之間休眠的秒數。

示例 1,將現有資料庫複製到另一個數據庫

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

src = sqlite3.connect('example.db')
dst = sqlite3.connect('backup.db')
with dst:
    src.backup(dst, pages=1, progress=progress)
dst.close()
src.close()

示例 2,將現有資料庫複製到瞬時副本

src = sqlite3.connect('example.db')
dst = sqlite3.connect(':memory:')
src.backup(dst)
dst.close()
src.close()

在 3.7 版本加入。

getlimit(category, /)

獲取連線執行時限制。

引數:

category (整數) – 要查詢的 SQLite 限制類別

返回型別:

int

引發:

ProgrammingError – 如果底層 SQLite 庫無法識別 *category*。

例如,查詢 Connection con 的 SQL 語句最大長度(預設為 1000000000)

>>> con.getlimit(sqlite3.SQLITE_LIMIT_SQL_LENGTH)
1000000000

在 3.11 版本中新增。

setlimit(category, limit, /)

設定連線執行時限制。嘗試將限制增加到其硬上限以上時,將靜默截斷為硬上限。無論限制是否更改,都返回限制的先前值。

引數:
返回型別:

int

引發:

ProgrammingError – 如果底層 SQLite 庫無法識別 *category*。

例如,將 Connection con 的附加資料庫數量限制為 1(預設限制為 10)

>>> con.setlimit(sqlite3.SQLITE_LIMIT_ATTACHED, 1)
10
>>> con.getlimit(sqlite3.SQLITE_LIMIT_ATTACHED)
1

在 3.11 版本中新增。

getconfig(op, /)

查詢布林連線配置選項。

引數:

op (整數) – 一個 SQLITE_DBCONFIG 程式碼

返回型別:

bool

3.12 新版功能.

setconfig(op, enable=True, /)

設定布林連線配置選項。

引數:

3.12 新版功能.

serialize(*, name='main')

將資料庫序列化為 bytes 物件。對於普通的磁碟資料庫檔案,序列化只是磁碟檔案的副本。對於記憶體資料庫或“臨時”資料庫,序列化是如果該資料庫被備份到磁碟時將寫入磁碟的相同位元組序列。

引數:

name (str) – 要序列化的資料庫名稱。預設為 "main"

返回型別:

bytes

備註

此方法僅在底層 SQLite 庫具有 serialize API 時可用。

在 3.11 版本中新增。

deserialize(data, /, *, name='main')

serialized 資料庫反序列化到 Connection 中。此方法會使資料庫連線從資料庫 name 斷開,然後根據 data 中包含的序列化將 name 作為記憶體資料庫重新開啟。

引數:
  • data (bytes) – 一個序列化的資料庫。

  • name (str) – 要反序列化的資料庫名稱。預設為 "main"

引發:

備註

此方法僅在底層 SQLite 庫具有 deserialize API 時可用。

在 3.11 版本中新增。

autocommit

此屬性控制符合 PEP 249 的事務行為。autocommit 有三個允許值

autocommit 更改為 False 將開啟一個新事務,更改為 True 將提交任何待處理的事務。

有關更多詳細資訊,請參閱 透過 autocommit 屬性控制事務

備註

除非 autocommit 設定為 LEGACY_TRANSACTION_CONTROL,否則 isolation_level 屬性無效。

3.12 新版功能.

in_transaction

此只讀屬性對應於低階 SQLite 自動提交模式

如果事務處於活動狀態(有未提交的更改),則為 True,否則為 False

在 3.2 版本加入。

isolation_level

控制 sqlite3舊式事務處理模式。如果設定為 None,則永遠不會隱式開啟事務。如果設定為 "DEFERRED""IMMEDIATE""EXCLUSIVE" 之一,對應於底層 SQLite 事務行為,則執行 隱式事務管理

如果未被 connect()isolation_level 引數覆蓋,則預設值為 "",它是 "DEFERRED" 的別名。

備註

建議使用 autocommit 控制事務處理,而不是使用 isolation_levelisolation_level 只有在 autocommit 設定為 LEGACY_TRANSACTION_CONTROL(預設值)時才有效。

row_factory

從此連線建立的 Cursor 物件的初始 row_factory。為此屬性賦值不會影響此連線現有遊標的 row_factory,僅影響新遊標。預設情況下為 None,這意味著每行作為 tuple 返回。

有關更多詳細資訊,請參閱 如何建立和使用行工廠

text_factory

一個 可呼叫物件,它接受一個 bytes 引數並返回其文字表示。對於資料型別為 TEXT 的 SQLite 值,將呼叫此可呼叫物件。預設情況下,此屬性設定為 str

有關更多詳細資訊,請參閱 如何處理非 UTF-8 文字編碼

total_changes

返回自資料庫連線開啟以來已修改、插入或刪除的資料庫行總數。

遊標物件

Cursor 物件表示一個 資料庫遊標,用於執行 SQL 語句和管理獲取操作的上下文。遊標是使用 Connection.cursor() 或使用任何 連線快捷方法 建立的。

遊標物件是 迭代器,這意味著如果您 execute() 一個 SELECT 查詢,您可以簡單地迭代遊標以獲取結果行

for row in cur.execute("SELECT t FROM data"):
    print(row)
class sqlite3.Cursor

Cursor 例項具有以下屬性和方法。

execute(sql, parameters=(), /)

執行單個 SQL 語句,可以選擇使用 佔位符 繫結 Python 值。

引數:
引發:

ProgrammingError – 當 sql 包含多個 SQL 語句時。當使用 命名佔位符parameters 是序列而不是 dict 時。

如果 autocommitLEGACY_TRANSACTION_CONTROLisolation_level 不是 NonesqlINSERTUPDATEDELETEREPLACE 語句,並且沒有開啟的事務,則在執行 sql 之前會隱式開啟一個事務。

3.14 版本中已更改: 如果使用 命名佔位符 並且 parameters 是序列而不是 dict,則會發出 ProgrammingError

使用 executescript() 執行多個 SQL 語句。

executemany(sql, parameters, /)

對於 parameters 中的每個專案,重複執行 引數化 DML SQL 語句 sql

使用與 execute() 相同的隱式事務處理。

引數:
引發:

ProgrammingError – 當 sql 包含多個 SQL 語句或不是 DML 語句時。當使用 命名佔位符 並且 parameters 中的專案是序列而不是 dict 時。

示例

rows = [
    ("row1",),
    ("row2",),
]
# cur is an sqlite3.Cursor object
cur.executemany("INSERT INTO data VALUES(?)", rows)

備註

任何結果行都將被丟棄,包括帶有 RETURNING 子句 的 DML 語句。

3.14 版本中已更改: 如果使用 命名佔位符 並且 parameters 中的專案是序列而不是 dict,則會發出 ProgrammingError

executescript(sql_script, /)

執行 sql_script 中的 SQL 語句。如果 autocommitLEGACY_TRANSACTION_CONTROL 並且存在待處理的事務,則首先執行隱式 COMMIT 語句。不執行其他隱式事務控制;任何事務控制都必須新增到 sql_script 中。

sql_script 必須是 string

示例

# cur is an sqlite3.Cursor object
cur.executescript("""
    BEGIN;
    CREATE TABLE person(firstname, lastname, age);
    CREATE TABLE book(title, author, published);
    CREATE TABLE publisher(name, address);
    COMMIT;
""")
fetchone()

如果 row_factoryNone,則將下一行查詢結果集作為 tuple 返回。否則,將其傳遞給行工廠並返回其結果。如果沒有更多資料可用,則返回 None

fetchmany(size=cursor.arraysize)

將查詢結果的下一組行作為 list 返回。如果沒有更多行可用,則返回空列表。

每次呼叫要獲取的行數由 size 引數指定。如果未給定 size,則 arraysize 確定要獲取的行數。如果可用的行數少於 size,則返回所有可用行。

請注意,size 引數涉及效能考慮。為了獲得最佳效能,通常最好使用 arraysize 屬性。如果使用 size 引數,那麼最好在每次 fetchmany() 呼叫中保持相同的值。

3.14.0(未釋出)版本中已更改: size 值將被拒絕,並引發 ValueError

fetchall()

將查詢結果的所有(剩餘)行作為 list 返回。如果沒有可用行,則返回空列表。請注意,arraysize 屬性可能會影響此操作的效能。

close()

立即關閉遊標(而不是在呼叫 __del__ 時)。

從此時起,遊標將無法使用;如果嘗試對遊標執行任何操作,將引發 ProgrammingError 異常。

setinputsizes(sizes, /)

DB-API 所必需。在 sqlite3 中不執行任何操作。

setoutputsize(size, column=None, /)

DB-API 所必需。在 sqlite3 中不執行任何操作。

arraysize

讀/寫屬性,控制 fetchmany() 返回的行數。預設值為 1,這意味著每次呼叫將獲取單行。

3.14.0(未釋出)版本中已更改: 負值將被拒絕,並引發 ValueError

connection

只讀屬性,提供屬於遊標的 SQLite 資料庫 Connection。透過呼叫 con.cursor() 建立的 Cursor 物件將具有一個引用 conconnection 屬性

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

只讀屬性,提供上次查詢的列名。為了與 Python DB API 相容,它為每列返回一個 7 元組,其中每個元組的最後六項為 None

對於沒有匹配行的 SELECT 語句,它也會被設定。

lastrowid

只讀屬性,提供最後插入行的行 ID。它僅在使用 execute() 方法成功執行 INSERTREPLACE 語句後更新。對於其他語句,在 executemany()executescript() 之後,或者如果插入失敗,lastrowid 的值保持不變。lastrowid 的初始值為 None

備註

WITHOUT ROWID 表的插入不記錄。

3.6 版本中已更改: 增加了對 REPLACE 語句的支援。

rowcount

只讀屬性,提供 INSERTUPDATEDELETEREPLACE 語句的修改行數;對於其他語句,包括 CTE 查詢,為 -1。它僅在語句執行完成後由 execute()executemany() 方法更新。這意味著必須獲取任何結果行才能更新 rowcount

row_factory

控制從 Cursor 獲取的行如何表示。如果為 None,則行表示為 tuple。可以設定為包含的 sqlite3.Row;或者是一個 可呼叫物件,它接受兩個引數:一個 Cursor 物件和行值 tuple,並返回一個表示 SQLite 行的自定義物件。

預設值為建立 CursorConnection.row_factory 的值。為此屬性賦值不會影響父連線的 Connection.row_factory

有關更多詳細資訊,請參閱 如何建立和使用行工廠

行物件

class sqlite3.Row

Row 例項作為 Connection 物件的高度最佳化的 row_factory。它支援迭代、相等測試、len(),以及透過列名和索引進行 對映 訪問。

如果兩個 Row 物件具有相同的列名和值,則它們相等。

有關更多詳細資訊,請參閱 如何建立和使用行工廠

keys()

返回一個 list,其中包含作為 strings 的列名。在查詢之後,它是 Cursor.description 中每個元組的第一個成員。

3.5 版本中已更改: 增加了對切片的支援。

Blob 物件

class sqlite3.Blob

在 3.11 版本中新增。

Blob 例項是一個 檔案類物件,可以讀寫 SQLite BLOB 中的資料。呼叫 len(blob) 獲取 blob 的大小(位元組數)。使用索引和 切片 直接訪問 blob 資料。

Blob 用作 上下文管理器 以確保在使用後關閉 blob 控制代碼。

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE test(blob_col blob)")
con.execute("INSERT INTO test(blob_col) VALUES(zeroblob(13))")

# Write to our blob, using two write operations:
with con.blobopen("test", "blob_col", 1) as blob:
    blob.write(b"hello, ")
    blob.write(b"world.")
    # Modify the first and last bytes of our blob
    blob[0] = ord("H")
    blob[-1] = ord("!")

# Read the contents of our blob
with con.blobopen("test", "blob_col", 1) as blob:
    greeting = blob.read()

print(greeting)  # outputs "b'Hello, world!'"
con.close()
close()

關閉 blob。

從此點起,blob 將無法使用。如果嘗試對 blob 執行任何進一步操作,將引發 Error(或其子類)異常。

read(length=-1, /)

從 blob 的當前偏移位置讀取 length 位元組的資料。如果到達 blob 末尾,將返回到 EOF 的資料。當未指定 length 或為負數時,read() 將一直讀取到 blob 的末尾。

write(data, /)

在當前偏移量處將 data 寫入 blob。此函式不能更改 blob 長度。寫入超出 blob 末尾將引發 ValueError

tell()

返回 blob 的當前訪問位置。

seek(offset, origin=os.SEEK_SET, /)

將 blob 的當前訪問位置設定為 offsetorigin 引數預設為 os.SEEK_SET(絕對 blob 定位)。origin 的其他值為 os.SEEK_CUR(相對於當前位置查詢)和 os.SEEK_END(相對於 blob 末尾查詢)。

PrepareProtocol 物件

class sqlite3.PrepareProtocol

PrepareProtocol 型別的唯一目的是作為 PEP 246 風格的適配協議,用於可以 自行適配 原生 SQLite 型別 的物件。

異常

異常層次結構由 DB-API 2.0(PEP 249)定義。

exception sqlite3.Warning

此異常目前不會由 sqlite3 模組引發,但可能會由使用 sqlite3 的應用程式引發,例如,如果使用者定義的函式在插入時截斷資料。WarningException 的子類。

exception sqlite3.Error

此模組中其他異常的基類。使用此異常可在單個 except 語句中捕獲所有錯誤。ErrorException 的子類。

如果異常源於 SQLite 庫內部,則以下兩個屬性將新增到異常中

sqlite_errorcode

來自 SQLite API 的數字錯誤程式碼

在 3.11 版本中新增。

sqlite_errorname

來自 SQLite API 的數字錯誤程式碼的符號名稱

在 3.11 版本中新增。

exception sqlite3.InterfaceError

由於誤用低階 SQLite C API 而引發的異常。換句話說,如果引發此異常,則可能表示 sqlite3 模組中存在錯誤。InterfaceErrorError 的子類。

exception sqlite3.DatabaseError

由於與資料庫相關的錯誤而引發的異常。這作為幾種資料庫錯誤的基異常。它僅透過專門的子類隱式引發。DatabaseErrorError 的子類。

exception sqlite3.DataError

由於處理資料的問題(例如數值超出範圍,字串過長)而引發的異常。DataErrorDatabaseError 的子類。

exception sqlite3.OperationalError

由於與資料庫操作相關的錯誤而引發的異常,不一定在程式設計師的控制之下。例如,找不到資料庫路徑,或者事務無法處理。OperationalErrorDatabaseError 的子類。

exception sqlite3.IntegrityError

當資料庫的參照完整性受到影響時(例如外部索引鍵檢查失敗)引發的異常。它是 DatabaseError 的子類。

exception sqlite3.InternalError

當 SQLite 遇到內部錯誤時引發的異常。如果引發此異常,可能表示執行時 SQLite 庫存在問題。InternalErrorDatabaseError 的子類。

exception sqlite3.ProgrammingError

由於 sqlite3 API 程式設計錯誤而引發的異常,例如向查詢提供錯誤的繫結數量,或嘗試對已關閉的 Connection 進行操作。ProgrammingErrorDatabaseError 的子類。

exception sqlite3.NotSupportedError

當底層 SQLite 庫不支援某個方法或資料庫 API 時引發的異常。例如,如果底層 SQLite 庫不支援確定性函式,則在 create_function() 中將 deterministic 設定為 TrueNotSupportedErrorDatabaseError 的子類。

SQLite 和 Python 型別

SQLite 原生支援以下型別:NULLINTEGERREALTEXTBLOB

因此,以下 Python 型別可以毫無問題地傳送到 SQLite

Python 型別

SQLite 型別

None

NULL

int

INTEGER

浮點數

REAL

str

TEXT

bytes

BLOB

SQLite 型別預設轉換為 Python 型別的方式如下

SQLite 型別

Python 型別

NULL

None

INTEGER

int

REAL

浮點數

TEXT

取決於 text_factory,預設為 str

BLOB

bytes

sqlite3 模組的型別系統可以透過兩種方式擴充套件:您可以透過 物件介面卡 在 SQLite 資料庫中儲存額外的 Python 型別,並且您可以透過 轉換器sqlite3 模組將 SQLite 型別轉換為 Python 型別。

預設介面卡和轉換器(已棄用)

備註

預設介面卡和轉換器自 Python 3.12 起已棄用。請改用 介面卡和轉換器示例 並根據您的需求進行調整。

已棄用的預設介面卡和轉換器包括

備註

預設的“timestamp”轉換器會忽略資料庫中的 UTC 偏移量,並始終返回一個 naive 的 datetime.datetime 物件。要保留時間戳中的 UTC 偏移量,可以停用轉換器,或者使用 register_converter() 註冊一個支援偏移量的轉換器。

自 3.12 版本起已棄用。

命令列介面

sqlite3 模組可以作為指令碼呼叫,使用直譯器的 -m 開關,以提供一個簡單的 SQLite shell。引數簽名如下

python -m sqlite3 [-h] [-v] [filename] [sql]

輸入 .quit 或 CTRL-D 退出 shell。

-h, --help

列印 CLI 幫助。

-v, --version

列印底層 SQLite 庫版本。

3.12 新版功能.

操作指南

如何在 SQL 查詢中使用佔位符繫結值

SQL 操作通常需要使用 Python 變數中的值。但是,請注意使用 Python 的字串操作來組裝查詢,因為它們容易受到 SQL 注入攻擊。例如,攻擊者可以簡單地關閉單引號並注入 OR TRUE 來選擇所有行

>>> # Never do this -- insecure!
>>> symbol = input()
' OR TRUE; --
>>> sql = "SELECT * FROM stocks WHERE symbol = '%s'" % symbol
>>> print(sql)
SELECT * FROM stocks WHERE symbol = '' OR TRUE; --'
>>> cur.execute(sql)

相反,請使用 DB-API 的引數替換。要將變數插入查詢字串,請在字串中使用佔位符,並透過將實際值作為 tuple 傳遞給遊標的 execute() 方法的第二個引數,將其替換到查詢中。

SQL 語句可以使用兩種佔位符之一:問號(qmark 風格)或命名佔位符(命名風格)。對於 qmark 風格,parameters 必須是一個 序列,其長度必須與佔位符的數量匹配,否則會引發 ProgrammingError。對於命名風格,parameters 必須是 dict(或其子類)的例項,其中必須包含所有命名引數的鍵;任何多餘的專案都將被忽略。以下是兩種風格的示例

con = sqlite3.connect(":memory:")
cur = con.execute("CREATE TABLE lang(name, first_appeared)")

# This is the named style used with executemany():
data = (
    {"name": "C", "year": 1972},
    {"name": "Fortran", "year": 1957},
    {"name": "Python", "year": 1991},
    {"name": "Go", "year": 2009},
)
cur.executemany("INSERT INTO lang VALUES(:name, :year)", data)

# This is the qmark style used in a SELECT query:
params = (1972,)
cur.execute("SELECT * FROM lang WHERE first_appeared = ?", params)
print(cur.fetchall())
con.close()

備註

PEP 249 數字佔位符 受支援。如果使用,它們將被解釋為命名佔位符。

如何將自定義 Python 型別適配為 SQLite 值

SQLite 原生僅支援有限的資料型別集。要將自定義 Python 型別儲存在 SQLite 資料庫中,請將它們 適配 為 SQLite 原生理解的 Python 型別 之一。

有兩種方法可以將 Python 物件適配到 SQLite 型別:讓您的物件自行適配,或者使用 介面卡可呼叫物件。後者將優先於前者。對於匯出自定義型別的庫,啟用該型別自行適配可能是有意義的。作為應用程式開發人員,透過註冊自定義介面卡函式進行直接控制可能更有意義。

如何編寫可適配物件

假設我們有一個 Point 類,它表示笛卡爾座標系中的一對座標 xy。座標對將作為文字字串儲存在資料庫中,使用分號分隔座標。這可以透過新增一個 __conform__(self, protocol) 方法來實現,該方法返回適配的值。傳遞給 protocol 的物件將是 PrepareProtocol 型別。

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

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

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

cur.execute("SELECT ?", (Point(4.0, -3.2),))
print(cur.fetchone()[0])
con.close()

如何註冊介面卡可呼叫物件

另一種可能性是建立一個將 Python 物件轉換為 SQLite 相容型別的函式。然後可以使用 register_adapter() 註冊此函式。

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

def adapt_point(point):
    return f"{point.x};{point.y}"

sqlite3.register_adapter(Point, adapt_point)

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

cur.execute("SELECT ?", (Point(1.0, 2.5),))
print(cur.fetchone()[0])
con.close()

如何將 SQLite 值轉換為自定義 Python 型別

編寫介面卡可讓您將自定義 Python 型別 轉換 為 SQLite 值。要將 SQLite 值 轉換 為自定義 Python 型別,我們使用 轉換器

讓我們回到 Point 類。我們以分號分隔的方式將 x 和 y 座標作為字串儲存在 SQLite 中。

首先,我們將定義一個轉換器函式,該函式接受字串作為引數並從中構造一個 Point 物件。

備註

轉換器函式 總是 傳遞一個 bytes 物件,無論底層 SQLite 資料型別如何。

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

我們現在需要告訴 sqlite3 何時應該轉換給定的 SQLite 值。這在連線到資料庫時完成,使用 connect()detect_types 引數。有三個選項

  • 隱式:將 detect_types 設定為 PARSE_DECLTYPES

  • 顯式:將 detect_types 設定為 PARSE_COLNAMES

  • 兩者:將 detect_types 設定為 sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES。列名優先於宣告的型別。

以下示例說明了隱式和顯式方法

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

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

def adapt_point(point):
    return f"{point.x};{point.y}"

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

# Register the adapter and converter
sqlite3.register_adapter(Point, adapt_point)
sqlite3.register_converter("point", convert_point)

# 1) Parse using declared types
p = Point(4.0, -3.2)
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.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()

# 2) Parse using column names
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.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()

介面卡和轉換器示例

本節展示了常見介面卡和轉換器的示例。

import datetime
import sqlite3

def adapt_date_iso(val):
    """Adapt datetime.date to ISO 8601 date."""
    return val.isoformat()

def adapt_datetime_iso(val):
    """Adapt datetime.datetime to timezone-naive ISO 8601 date."""
    return val.replace(tzinfo=None).isoformat()

def adapt_datetime_epoch(val):
    """Adapt datetime.datetime to Unix timestamp."""
    return int(val.timestamp())

sqlite3.register_adapter(datetime.date, adapt_date_iso)
sqlite3.register_adapter(datetime.datetime, adapt_datetime_iso)
sqlite3.register_adapter(datetime.datetime, adapt_datetime_epoch)

def convert_date(val):
    """Convert ISO 8601 date to datetime.date object."""
    return datetime.date.fromisoformat(val.decode())

def convert_datetime(val):
    """Convert ISO 8601 datetime to datetime.datetime object."""
    return datetime.datetime.fromisoformat(val.decode())

def convert_timestamp(val):
    """Convert Unix epoch timestamp to datetime.datetime object."""
    return datetime.datetime.fromtimestamp(int(val))

sqlite3.register_converter("date", convert_date)
sqlite3.register_converter("datetime", convert_datetime)
sqlite3.register_converter("timestamp", convert_timestamp)

如何使用連線快捷方法

透過使用 Connection 類的 execute()executemany()executescript() 方法,您的程式碼可以寫得更簡潔,因為您不必顯式建立(通常是多餘的)Cursor 物件。相反,Cursor 物件會被隱式建立,並且這些快捷方法會返回遊標物件。這樣,您只需在 Connection 物件上進行一次呼叫,即可執行 SELECT 語句並直接遍歷它。

# Create and fill the table.
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE lang(name, first_appeared)")
data = [
    ("C++", 1985),
    ("Objective-C", 1984),
]
con.executemany("INSERT INTO lang(name, first_appeared) VALUES(?, ?)", data)

# Print the table contents
for row in con.execute("SELECT name, first_appeared FROM lang"):
    print(row)

print("I just deleted", con.execute("DELETE FROM lang").rowcount, "rows")

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

如何使用連線上下文管理器

一個 Connection 物件可以用作上下文管理器,當離開上下文管理器的作用域時,它會自動提交或回滾未完成的事務。如果 with 語句的主體在沒有異常的情況下完成,則事務被提交。如果此提交失敗,或者 with 語句的主體引發了未捕獲的異常,則事務將回滾。如果 autocommitFalse,則在提交或回滾後會隱式開啟一個新事務。

如果在離開 with 語句的主體時沒有未完成的事務,或者如果 autocommitTrue,則上下文管理器不執行任何操作。

備註

上下文管理器既不隱式開啟新事務,也不關閉連線。如果您需要一個關閉連線的上下文管理器,請考慮使用 contextlib.closing()

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE lang(id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)")

# Successful, con.commit() is called automatically afterwards
with con:
    con.execute("INSERT INTO lang(name) VALUES(?)", ("Python",))

# 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 lang(name) VALUES(?)", ("Python",))
except sqlite3.IntegrityError:
    print("couldn't add Python twice")

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

如何使用 SQLite URI

一些有用的 URI 技巧包括

  • 以只讀模式開啟資料庫

>>> con = sqlite3.connect("file:tutorial.db?mode=ro", uri=True)
>>> con.execute("CREATE TABLE readonly(data)")
Traceback (most recent call last):
OperationalError: attempt to write a readonly database
>>> con.close()
  • 如果資料庫檔案不存在,則不隱式建立新檔案;如果無法建立新檔案,將引發 OperationalError

>>> con = sqlite3.connect("file:nosuchdb.db?mode=rw", uri=True)
Traceback (most recent call last):
OperationalError: unable to open database file
  • 建立一個共享的命名記憶體資料庫

db = "file:mem1?mode=memory&cache=shared"
con1 = sqlite3.connect(db, uri=True)
con2 = sqlite3.connect(db, uri=True)
with con1:
    con1.execute("CREATE TABLE shared(data)")
    con1.execute("INSERT INTO shared VALUES(28)")
res = con2.execute("SELECT data FROM shared")
assert res.fetchone() == (28,)

con1.close()
con2.close()

有關此功能的更多資訊,包括引數列表,可以在 SQLite URI 文件中找到。

如何建立和使用行工廠

預設情況下,sqlite3 將每一行表示為一個 tuple。如果 tuple 不符合您的需求,您可以使用 sqlite3.Row 類或自定義的 row_factory

雖然 row_factory 作為屬性存在於 CursorConnection 上,但建議設定 Connection.row_factory,以便從該連線建立的所有遊標都使用相同的行工廠。

Row 提供對列的索引和不區分大小寫的命名訪問,與 tuple 相比,記憶體開銷和效能影響極小。要將 Row 用作行工廠,請將其分配給 row_factory 屬性

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

查詢現在返回 Row 物件

>>> res = con.execute("SELECT 'Earth' AS name, 6378 AS radius")
>>> row = res.fetchone()
>>> row.keys()
['name', 'radius']
>>> row[0]         # Access by index.
'Earth'
>>> row["name"]    # Access by name.
'Earth'
>>> row["RADIUS"]  # Column names are case-insensitive.
6378
>>> con.close()

備註

SELECT 語句中可以省略 FROM 子句,如上例所示。在這種情況下,SQLite 返回一行,其中列由表示式(例如字面量)定義,並帶有給定的別名 expr AS alias

您可以建立一個自定義的 row_factory,它將每一行作為 dict 返回,其中列名對映到值

def dict_factory(cursor, row):
    fields = [column[0] for column in cursor.description]
    return {key: value for key, value in zip(fields, row)}

使用它,查詢現在返回一個 dict 而不是一個 tuple

>>> con = sqlite3.connect(":memory:")
>>> con.row_factory = dict_factory
>>> for row in con.execute("SELECT 1 AS a, 2 AS b"):
...     print(row)
{'a': 1, 'b': 2}
>>> con.close()

以下行工廠返回一個 命名元組

from collections import namedtuple

def namedtuple_factory(cursor, row):
    fields = [column[0] for column in cursor.description]
    cls = namedtuple("Row", fields)
    return cls._make(row)

namedtuple_factory() 可以按如下方式使用

>>> con = sqlite3.connect(":memory:")
>>> con.row_factory = namedtuple_factory
>>> cur = con.execute("SELECT 1 AS a, 2 AS b")
>>> row = cur.fetchone()
>>> row
Row(a=1, b=2)
>>> row[0]  # Indexed access.
1
>>> row.b   # Attribute access.
2
>>> con.close()

經過一些調整,上述方法可以修改為使用 dataclass 或任何其他自定義類,而不是 namedtuple

如何處理非 UTF-8 文字編碼

預設情況下,sqlite3 使用 str 來適配資料型別為 TEXT 的 SQLite 值。這對於 UTF-8 編碼的文字工作良好,但對於其他編碼和無效的 UTF-8 可能會失敗。您可以使用自定義的 text_factory 來處理此類情況。

由於 SQLite 的 靈活型別,遇到包含非 UTF-8 編碼甚至任意資料的 TEXT 資料型別的表列並不少見。為了演示,假設我們有一個包含 ISO-8859-2 (Latin-2) 編碼文字的資料庫,例如一個捷克-英語詞典條目表。假設我們現在有一個連線到該資料庫的 Connection 例項 con,我們可以使用此 text_factory 解碼 Latin-2 編碼的文字

con.text_factory = lambda data: str(data, encoding="latin2")

對於儲存在 TEXT 表列中的無效 UTF-8 或任意資料,您可以使用以下技術,借鑑自 Unicode HOWTO

con.text_factory = lambda data: str(data, errors="surrogateescape")

備註

sqlite3 模組 API 不支援包含代理字元的字串。

說明

事務控制

sqlite3 提供了多種控制資料庫事務何時、如何開啟和關閉的方法。透過 autocommit 屬性進行事務控制 是推薦的方法,而 透過 isolation_level 屬性進行事務控制 保留了 Python 3.12 之前的行為。

透過 autocommit 屬性進行事務控制

控制事務行為的推薦方式是透過 Connection.autocommit 屬性,最好使用 connect()autocommit 引數進行設定。

建議將 autocommit 設定為 False,這意味著符合 PEP 249 規範的事務控制。這意味著

  • sqlite3 確保事務始終處於開啟狀態,因此 connect()Connection.commit()Connection.rollback() 將隱式開啟一個新事務(後兩者在關閉掛起事務後立即開啟)。sqlite3 在開啟事務時使用 BEGIN DEFERRED 語句。

  • 事務應使用 commit() 顯式提交。

  • 事務應使用 rollback() 顯式回滾。

  • 如果資料庫在存在掛起更改的情況下 close(),將執行隱式回滾。

autocommit 設定為 True 以啟用 SQLite 的 自動提交模式。在此模式下,Connection.commit()Connection.rollback() 無效。請注意,SQLite 的自動提交模式與符合 PEP 249 規範的 Connection.autocommit 屬性不同;使用 Connection.in_transaction 查詢底層 SQLite 自動提交模式。

autocommit 設定為 LEGACY_TRANSACTION_CONTROL 以將事務控制行為留給 Connection.isolation_level 屬性。有關更多資訊,請參閱 透過 isolation_level 屬性進行事務控制

透過 isolation_level 屬性進行事務控制

備註

控制事務的推薦方式是透過 autocommit 屬性。請參閱 透過 autocommit 屬性進行事務控制

如果 Connection.autocommit 設定為 LEGACY_TRANSACTION_CONTROL (預設值),則事務行為由 Connection.isolation_level 屬性控制。否則,isolation_level 無效。

如果連線屬性 isolation_level 不是 None,則在 execute()executemany() 執行 INSERTUPDATEDELETEREPLACE 語句之前會隱式開啟新事務;對於其他語句,不執行隱式事務處理。使用 commit()rollback() 方法分別提交和回滾掛起事務。您可以透過 isolation_level 屬性選擇底層的 SQLite 事務行為 —— 即 sqlite3 是否以及隱式執行何種型別的 BEGIN 語句。

如果 isolation_level 設定為 None,則根本不隱式開啟事務。這使得底層的 SQLite 庫處於 自動提交模式,但也允許使用者使用顯式 SQL 語句執行自己的事務處理。可以使用 in_transaction 屬性查詢底層的 SQLite 自動提交模式。

無論 isolation_level 的值如何,executescript() 方法在執行給定的 SQL 指令碼之前都會隱式提交任何掛起事務。

3.6 版本變更: sqlite3 過去會在 DDL 語句之前隱式提交一個未完成的事務。現在不再是這樣了。

3.12 版本變更: 現在推薦透過 autocommit 屬性來控制事務。