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.org.cn/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 属性来控制事务。