ZetCode

Python sqlite3.ProgrammingError 异常

上次修改时间:2025 年 4 月 15 日

本综合指南探讨了 Python 的 sqlite3.ProgrammingError 异常,该异常在检测到不正确的 API 使用时发生。 我们将涵盖常见原因、错误处理模式和实际示例。

基本定义

sqlite3.ProgrammingErrorsqlite3.Error 的一个子类,表示 SQLite 数据库操作中的编程错误。 它通常是由于不正确的 API 使用而不是数据库错误而发生的。

主要特征:它表示开发人员的错误,例如无效的 SQL 语法、不正确的参数绑定或不正确的资源使用。 它在任何 SQL 执行到达数据库引擎之前引发。

无效的 SQL 语法

此示例演示了格式错误的 SQL 语句如何引发 ProgrammingError。 错误发生在执行之前的语句准备期间。

invalid_syntax.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        cursor = conn.cursor()
        # Missing closing parenthesis
        cursor.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT")
except sqlite3.ProgrammingError as e:
    print(f"ProgrammingError occurred: {e}")

发生错误的原因是 SQL 语句在语法上不正确。 缺少右括号会在语句准备期间触发异常。

始终在执行之前验证 SQL 语法。 使用 SQL linter 或数据库 GUI 客户端等工具来独立测试查询。

不正确的参数绑定

当由于占位符和参数不匹配而导致参数绑定失败时,会引发 ProgrammingError。

parameter_binding.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        cursor = conn.cursor()
        cursor.execute("CREATE TABLE test (id INTEGER, name TEXT)")
        # Mismatch between placeholders (2) and parameters (1)
        cursor.execute("INSERT INTO test VALUES (?, ?)", (1,))
except sqlite3.ProgrammingError as e:
    print(f"Parameter binding error: {e}")

该示例显示了一个常见错误,其中占位符的数量与提供的参数数量不匹配。 错误发生在参数绑定期间。

始终确保参数计数与占位符匹配。 考虑对复杂查询使用命名参数,以提高可读性并减少错误。

已关闭游标的使用

尝试使用已关闭的游标会引发 ProgrammingError。 此示例演示了正确的资源管理。

closed_cursor.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE data (value TEXT)")
    cursor.close()  # Explicitly close cursor
    
    try:
        # Attempt to use closed cursor
        cursor.execute("INSERT INTO data VALUES ('test')")
    except sqlite3.ProgrammingError as e:
        print(f"Closed cursor error: {e}")

尝试使用显式关闭的游标执行 SQL 时发生错误。 游标在关闭后变为无效,无法重复使用。

with 语句在块退出时自动关闭游标。 仅在特定场景(例如长时间运行的连接)中才需要显式关闭。

无效的列操作

尝试对不存在的列或表执行操作时,会发生 ProgrammingError。 此示例显示了正确的错误处理。

invalid_column.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        cursor = conn.cursor()
        cursor.execute("CREATE TABLE products (id INTEGER, name TEXT)")
        # Non-existent column 'price'
        cursor.execute("SELECT price FROM products")
except sqlite3.ProgrammingError as e:
    print(f"Column error: {e}")

发生错误的原因是查询引用了表中不存在的列。 数据库引擎在语句准备期间检测到这一点。

在编写查询之前,始终验证表架构。 必要时使用 PRAGMA table_info 以编程方式检查表结构。

事务管理错误

不正确的事务管理可能会引发 ProgrammingError。 此示例显示了正确的事务处理。

transaction_error.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        conn.isolation_level = None  # Autocommit mode
        cursor = conn.cursor()
        # Attempt to commit when not in transaction
        conn.commit()
except sqlite3.ProgrammingError as e:
    print(f"Transaction error: {e}")

发生错误的原因是在没有活动事务时调用了 commit。 在自动提交模式 (isolation_level=None) 下,显式提交是不必要的,并且会引发错误。

了解您的隔离级别设置。 尽可能对事务使用上下文管理器,以避免手动 commit/rollback 调用。

资源清理错误

在不正确的资源清理期间可能会发生 ProgrammingError。 此示例显示了正确的资源管理模式。

resource_cleanup.py
import sqlite3

try:
    conn = sqlite3.connect(':memory:')
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE temp (id INTEGER)")
    conn.close()  # Close connection first
    
    # Attempt to use cursor after connection closed
    cursor.execute("SELECT * FROM temp")
except sqlite3.ProgrammingError as e:
    print(f"Resource error: {e}")
finally:
    cursor.close()  # Still need to close cursor

发生错误的原因是在其父连接关闭后使用了游标。 游标依赖于其连接,并在连接关闭时变为无效。

始终以相反的顺序关闭资源:先关闭游标,然后关闭连接。 更好的是,使用上下文管理器来自动处理清理。

类型不匹配错误

ProgrammingError 可以在参数绑定期间发出类型不匹配信号。 此示例演示了正确的类型处理。

type_mismatch.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        cursor = conn.cursor()
        cursor.execute("CREATE TABLE items (id INTEGER, data BLOB)")
        # Incorrect parameter type for BLOB
        cursor.execute("INSERT INTO items VALUES (?, ?)", 
                      (1, "string instead of bytes"))
except sqlite3.ProgrammingError as e:
    print(f"Type error: {e}")

发生错误的原因是为 BLOB 列提供了字符串而不是字节。 SQLite 在参数绑定期间执行类型检查。

始终将 Python 类型与 SQLite 列类型匹配。 在绑定之前适当地转换数据,尤其是对于 BLOB 和数字类型。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程