ZetCode

Python sqlite3.OperationalError 异常

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

本综合指南探讨了 Python 的 sqlite3.OperationalError 异常,该异常在数据库操作期间发生。我们将介绍常见原因、处理技巧和使用上下文管理器的实际示例。

基本定义

当 SQLite 遇到无法完成的操作时,会引发 sqlite3.OperationalError。 这包括语法错误、缺少表或数据库锁。 它是 sqlite3.Error 的子类。

常见原因:无效的 SQL 语法、缺少数据库对象、权限问题或锁定的数据库。 正确的处理可确保健壮的数据库应用程序。

尝试访问不存在的表

此示例演示了尝试查询不存在的表时发生的错误。 我们将使用上下文管理器进行自动资源清理。

nonexistent_table.py
import sqlite3

try:
    with sqlite3.connect('test.db') as conn:
        cursor = conn.cursor()
        # This table doesn't exist yet
        cursor.execute("SELECT * FROM nonexistent_table")
except sqlite3.OperationalError as e:
    print(f"OperationalError occurred: {e}")

发生错误的原因是我们尝试在创建表之前从中进行选择。 即使发生错误,上下文管理器也可确保正确关闭连接。

输出将显示“no such table: nonexistent_table”。 在运行查询之前,请务必检查您的数据库模式。

无效的 SQL 语法

此示例显示了执行具有语法错误的 SQL 时发生的错误。 我们将使用上下文管理器进行适当的资源管理。

invalid_syntax.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        with conn.cursor() as cursor:
            # Missing column list in CREATE TABLE
            cursor.execute("CREATE TABLE")
except sqlite3.OperationalError as e:
    print(f"Syntax error: {e}")

发生错误的原因是不完整的 CREATE TABLE 语句。 嵌套的上下文管理器会自动处理连接和游标清理。

输出将指示“CREATE TABLE”附近的语法错误。 执行前务必验证您的 SQL 语句。

数据库锁定错误

此示例演示了处理锁定的数据库场景,这在多进程应用程序中很常见。

locked_database.py
import sqlite3
import time

def worker(db_file):
    with sqlite3.connect(db_file) as conn:
        conn.execute("BEGIN EXCLUSIVE")
        print("Worker locked database")
        time.sleep(2)  # Simulate long operation
        conn.execute("CREATE TABLE IF NOT EXISTS tasks (id INTEGER)")
        conn.commit()

try:
    # Simulate concurrent access
    import threading
    thread = threading.Thread(target=worker, args=('locked.db',))
    thread.start()
    
    time.sleep(0.5)  # Let worker lock first
    with sqlite3.connect('locked.db', timeout=1) as conn:
        conn.execute("SELECT * FROM sqlite_master")
except sqlite3.OperationalError as e:
    print(f"Database locked error: {e}")
thread.join()

发生错误的原因是第二个连接无法在超时时间内获取锁。 尽管发生错误,上下文管理器仍可确保正确清理。

输出将显示“database is locked”。 考虑增加超时或重新设计并发访问模式。

只读数据库错误

此示例显示了处理尝试写入只读数据库文件的操作。 我们将使用上下文管理器来确保资源安全。

readonly_database.py
import sqlite3
import os

# Create read-only file
with open('readonly.db', 'w') as f:
    f.write("")  # Empty database
os.chmod('readonly.db', 0o444)  # Read-only permissions

try:
    with sqlite3.connect('readonly.db') as conn:
        conn.execute("CREATE TABLE test (id INTEGER)")
except sqlite3.OperationalError as e:
    print(f"Read-only error: {e}")
finally:
    os.chmod('readonly.db', 0o644)  # Cleanup
    os.remove('readonly.db')

发生错误的原因是尝试修改只读文件。 尽管发生错误,上下文管理器仍可确保关闭连接。

输出将指示“attempt to write a readonly database”。 在数据库操作之前检查文件权限。

缺少数据库文件

此示例演示了处理数据库文件缺失时的错误,即使 SQLite 通常会自动创建新文件。

missing_database.py
import sqlite3

def connect_with_check(db_file):
    try:
        with sqlite3.connect(f'file:{db_file}?mode=rw', uri=True) as conn:
            return conn
    except sqlite3.OperationalError as e:
        print(f"Database access error: {e}")
        return None

conn = connect_with_check('missing.db')
if conn:
    conn.execute("CREATE TABLE test (id INTEGER)")

发生错误的原因是我们显式请求对不存在的文件使用读写模式。 URI 连接字符串提供了对打开行为的更多控制。

输出将显示“unable to open database file”。 使用 URI 模式可以精确控制数据库打开行为。

事务处理错误

此示例显示了因事务处理不当可能发生的错误,使用上下文管理器来确保安全。

transaction_error.py
import sqlite3

try:
    with sqlite3.connect('transactions.db') as conn:
        conn.isolation_level = None  # Autocommit mode
        conn.execute("BEGIN")
        conn.execute("CREATE TABLE IF NOT EXISTS logs (message TEXT)")
        # Forgot to commit or rollback
        conn.execute("BEGIN")  # Nested transaction
except sqlite3.OperationalError as e:
    print(f"Transaction error: {e}")

发生错误的原因是嵌套事务没有正确完成。 尽管发生事务错误,上下文管理器仍可确保关闭连接。

输出将指示“cannot start a transaction within a transaction”。 务必在启动新事务之前完成事务。

列计数不匹配

此示例演示了处理插入的数据与表结构不匹配时发生的错误,使用上下文管理器进行清理。

column_mismatch.py
import sqlite3

try:
    with sqlite3.connect(':memory:') as conn:
        conn.execute("CREATE TABLE products (id INTEGER, name TEXT)")
        # Wrong number of values
        conn.execute("INSERT INTO products VALUES (1, 'Phone', 999)")
except sqlite3.OperationalError as e:
    print(f"Column mismatch error: {e}")

发生错误的原因是我们为 2 列的表提供了 3 个值。 上下文管理器会自动处理资源清理。

输出将显示“table products has 2 columns but 3 values were supplied”。 务必使您的数据与表结构匹配。

最佳实践

资料来源

作者

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

列出所有 Python 教程