Python sqlite3.Connection.set_trace_callback 方法
上次修改时间:2025 年 4 月 15 日
这篇综合指南探讨了 Python 的 sqlite3.Connection.set_trace_callback
方法,它允许追踪连接执行的 SQL 语句。我们将涵盖基本用法、实际示例和调试技巧。
基本定义
set_trace_callback
方法注册一个回调函数,该函数针对连接执行的每个 SQL 语句被调用。 它对于调试、日志记录或分析 SQL 查询很有用。
主要特点:回调函数接收 SQL 文本作为字符串,它在语句执行之前被调用,并且可以用于监视所有数据库操作。可以将回调函数设置为 None 以禁用跟踪。
基本跟踪回调示例
此示例演示如何设置一个简单的跟踪回调,该回调在执行之前打印所有 SQL 语句。
import sqlite3 def trace_callback(sql): print(f"Executing SQL: {sql}") with sqlite3.connect(":memory:") as conn: conn.set_trace_callback(trace_callback) cursor = conn.cursor() cursor.execute("CREATE TABLE users (id INTEGER, name TEXT)") cursor.execute("INSERT INTO users VALUES (1, 'Alice')") cursor.execute("SELECT * FROM users") print(cursor.fetchall())
跟踪回调在执行之前打印每个 SQL 语句。 这有助于了解正在数据库上执行哪些操作。
输出将按顺序显示 CREATE TABLE、INSERT 和 SELECT 语句,然后是查询结果。 回调函数接收确切的 SQL 文本。
过滤特定 SQL 语句
此示例展示了如何使用跟踪回调来过滤和处理特定类型的 SQL 语句。
import sqlite3 def trace_callback(sql): sql_lower = sql.lower() if "insert" in sql_lower: print(f"Insert operation detected: {sql}") elif "select" in sql_lower: print(f"Select operation detected: {sql}") with sqlite3.connect(":memory:") as conn: conn.set_trace_callback(trace_callback) cursor = conn.cursor() cursor.execute("CREATE TABLE logs (id INTEGER, message TEXT)") cursor.execute("INSERT INTO logs VALUES (1, 'Startup')") cursor.execute("SELECT * FROM logs") cursor.execute("DELETE FROM logs WHERE id = 1") conn.commit()
回调函数现在检查特定的 SQL 关键字,并且仅打印包含这些关键字的语句。 这对于监视特定操作很有用。
请注意,回调函数仍然接收所有语句,但我们有选择地仅处理我们感兴趣的语句。 此处不会打印 DELETE 语句。
测量查询执行时间
此示例演示如何使用带有时间测量的跟踪回调来分析查询性能。
import sqlite3 import time class QueryTimer: def __init__(self): self.start_time = None def trace_callback(self, sql): self.start_time = time.time() print(f"Starting query: {sql}") def print_duration(self): if self.start_time: duration = (time.time() - self.start_time) * 1000 print(f"Query completed in {duration:.2f} ms\n") timer = QueryTimer() with sqlite3.connect(":memory:") as conn: conn.set_trace_callback(timer.trace_callback) cursor = conn.cursor() # Create and populate a table cursor.execute("CREATE TABLE data (id INTEGER, value REAL)") cursor.executemany("INSERT INTO data VALUES (?, ?)", [(i, i * 1.5) for i in range(1000)]) timer.print_duration() # Run a query cursor.execute("SELECT AVG(value) FROM data") timer.print_duration() print("Average:", cursor.fetchone()[0])
此示例使用一个类来跟踪查询开始时间并测量持续时间。 跟踪回调记录查询开始的时间,我们测量之后的经过时间。
输出显示正在执行的 SQL 以及每个操作花费的时间。 这对于性能优化和识别慢查询很有价值。
统计数据库操作
此示例使用跟踪回调来统计会话期间执行的不同类型的数据库操作。
import sqlite3 class OperationCounter: def __init__(self): self.counts = { 'select': 0, 'insert': 0, 'update': 0, 'delete': 0, 'other': 0 } def trace_callback(self, sql): sql_lower = sql.lower() if "select" in sql_lower: self.counts['select'] += 1 elif "insert" in sql_lower: self.counts['insert'] += 1 elif "update" in sql_lower: self.counts['update'] += 1 elif "delete" in sql_lower: self.counts['delete'] += 1 else: self.counts['other'] += 1 def print_counts(self): print("Database operation counts:") for op, count in self.counts.items(): print(f"{op.capitalize()}: {count}") counter = OperationCounter() with sqlite3.connect(":memory:") as conn: conn.set_trace_callback(counter.trace_callback) cursor = conn.cursor() cursor.execute("CREATE TABLE products (id INTEGER, name TEXT, price REAL)") cursor.executemany("INSERT INTO products VALUES (?, ?, ?)", [(1, 'Apple', 1.2), (2, 'Banana', 0.8)]) cursor.execute("UPDATE products SET price = 1.3 WHERE name = 'Apple'") cursor.execute("SELECT * FROM products") cursor.execute("SELECT COUNT(*) FROM products") cursor.execute("DELETE FROM products WHERE price > 1.0") counter.print_counts()
OperationCounter 类维护不同 SQL 操作类型的计数。 跟踪回调为每个语句增加相应的计数器。
这对于了解数据库上的工作负载模式很有用,这有助于优化和资源规划。 最终计数在最后打印。
将 SQL 语句记录到文件
此示例展示了如何使用跟踪回调将所有 SQL 语句记录到文件,这对于审计或调试很有用。
import sqlite3 from datetime import datetime class SQLLogger: def __init__(self, filename): self.log_file = open(filename, 'a') def trace_callback(self, sql): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.log_file.write(f"[{timestamp}] {sql}\n") self.log_file.flush() def close(self): self.log_file.close() logger = SQLLogger("sql_log.txt") try: with sqlite3.connect(":memory:") as conn: conn.set_trace_callback(logger.trace_callback) cursor = conn.cursor() cursor.execute("CREATE TABLE events (id INTEGER, ts TEXT, desc TEXT)") cursor.execute("INSERT INTO events VALUES (1, datetime('now'), 'Start')") cursor.execute("SELECT * FROM events") # Simulate an error try: cursor.execute("INVALID SQL STATEMENT") except sqlite3.OperationalError: pass finally: logger.close() print("SQL statements logged to sql_log.txt")
SQLLogger 类将每个 SQL 语句以及时间戳写入文件。 这会创建所有数据库操作的审计跟踪,包括其时间安排。
日志文件对于调试问题非常有价值,尤其是在生产环境中,您需要了解问题发生之前发生了什么。 文件在 finally 块中正确关闭。
检测潜在的 SQL 注入
此示例演示如何通过在 SQL 语句中查找可疑模式,使用跟踪回调来检测潜在的 SQL 注入尝试。
import sqlite3 import re class InjectionDetector: def __init__(self): self.suspicious_patterns = [ r";\s*--", r";\s*#", r"union\s+select", r"1\s*=\s*1", r"sleep\s*\(" ] def trace_callback(self, sql): for pattern in self.suspicious_patterns: if re.search(pattern, sql, re.IGNORECASE): print(f"WARNING: Potential SQL injection detected!") print(f"Suspicious SQL: {sql}") break detector = InjectionDetector() with sqlite3.connect(":memory:") as conn: conn.set_trace_callback(detector.trace_callback) cursor = conn.cursor() # Safe queries cursor.execute("CREATE TABLE accounts (id INTEGER, username TEXT)") cursor.execute("INSERT INTO accounts VALUES (?, ?)", (1, "admin")) # Simulate suspicious query (would be from user input in real scenario) user_input = "admin' OR 1=1--" try: cursor.execute(f"SELECT * FROM accounts WHERE username = '{user_input}'") except sqlite3.OperationalError: pass # Another suspicious pattern cursor.execute("SELECT * FROM accounts WHERE username = 'admin' UNION SELECT 1, 2")
InjectionDetector 类针对已知的可疑模式检查每个 SQL 语句,这些模式可能表明 SQL 注入尝试。 找到时,它会打印警告。
虽然这是一个简单的示例,但它演示了如何将跟踪回调用于安全监视。 在生产中,您需要更复杂的检测和适当的警报。
将跟踪回调与连接钩子结合使用
此高级示例展示了如何将跟踪回调与其他 SQLite 连接钩子结合使用,以实现全面的监视。
import sqlite3 class DatabaseMonitor: def __init__(self): self.total_queries = 0 def trace_callback(self, sql): self.total_queries += 1 print(f"Query #{self.total_queries}: {sql}") def progress_handler(self): print("Database operation in progress...") return 0 # Return non-zero to abort operation def commit_hook(self): print("Commit about to be executed") return 0 # Return non-zero to abort commit def rollback_hook(self): print("Rollback occurred") monitor = DatabaseMonitor() with sqlite3.connect(":memory:") as conn: # Set up all hooks conn.set_trace_callback(monitor.trace_callback) conn.set_progress_handler(monitor.progress_handler, 100) conn.commit_hook = monitor.commit_hook conn.rollback_hook = monitor.rollback_hook cursor = conn.cursor() # Perform operations that will trigger hooks cursor.execute("CREATE TABLE test (id INTEGER)") for i in range(150): cursor.execute("INSERT INTO test VALUES (?)", (i,)) conn.commit() # Force a rollback try: cursor.execute("INVALID SQL") conn.commit() except sqlite3.OperationalError: conn.rollback() print(f"Total queries executed: {monitor.total_queries}")
此示例将跟踪回调与 SQLite 的进度处理程序、提交钩子和回滚钩子结合在一起,以创建一个全面的监视解决方案。
进度处理程序在长时间操作期间定期调用,而提交和回滚钩子提供事务生命周期监视。 结合跟踪回调,这可以完全了解数据库活动。
最佳实践
- 保持回调快速: 它们在查询期间同步执行
- 用于调试: 考虑在生产环境中禁用
- 与日志记录结合使用: 用于持久跟踪记录
- 处理异常: 回调中的错误可能会导致您的应用崩溃
- 完成后重置: 在不需要时将回调设置为 None
资料来源
作者
列出所有 Python 教程。