Python sqlite3.Cursor.rowcount 属性
上次修改时间:2025 年 4 月 15 日
本综合指南探讨了 Python 的 sqlite3.Cursor.rowcount
属性,该属性返回上次操作修改的行数。我们将介绍其行为、局限性和实际使用示例。
基本定义
SQLite 游标的 rowcount
属性返回受上次执行操作影响的行数。它对于 UPDATE、DELETE 和 INSERT 语句很有用。
主要特点:它是只读的,如果没有执行任何操作或对于 SELECT 语句,则返回 -1,并且仅反映最近一次操作的影响。
基本 rowcount 示例
此示例演示了 UPDATE 操作后 rowcount
的基本用法。
import sqlite3 with sqlite3.connect('example.db') as conn: conn.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)''') conn.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)") conn.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)") cursor = conn.cursor() cursor.execute("UPDATE users SET age = age + 1 WHERE name LIKE 'A%'") print(f"Rows updated: {cursor.rowcount}") # Output: 1
该示例表明 rowcount
正确报告更新了 1 行。由于 WHERE 子句,UPDATE 操作仅影响了 Alice 的记录。
请注意我们如何使用上下文管理器 (with
) 来自动处理连接清理,确保正确释放资源。
带有 DELETE 操作的 rowcount
此示例演示了 DELETE 操作后 rowcount
的用法。
import sqlite3 with sqlite3.connect('example.db') as conn: cursor = conn.cursor() # Setup test data cursor.executescript(''' DROP TABLE IF EXISTS products; CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO products (name) VALUES ('Laptop'), ('Phone'), ('Tablet'); ''') # Delete operation cursor.execute("DELETE FROM products WHERE name LIKE 'P%'") print(f"Rows deleted: {cursor.rowcount}") # Output: 1
DELETE 操作仅删除“Phone”产品,因此 rowcount
返回 1。该示例还展示了如何使用 executescript
处理多个语句。
即使发生错误,上下文管理器也能确保在操作完成后正确关闭连接和游标,防止资源泄漏。
带有 INSERT 操作的 rowcount
此示例显示了 rowcount
在 INSERT 操作中的行为。
import sqlite3 with sqlite3.connect('example.db') as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, product TEXT, quantity INTEGER)''') # Single row insert cursor.execute("INSERT INTO orders (product, quantity) VALUES ('Book', 2)") print(f"Rows inserted (single): {cursor.rowcount}") # Output: 1 # Multiple rows insert cursor.executemany("INSERT INTO orders (product, quantity) VALUES (?, ?)", [('Pen', 10), ('Pencil', 15)]) print(f"Rows inserted (multiple): {cursor.rowcount}") # Output: 1 (last operation only)
对于单个 INSERT,rowcount
正确报告 1。但是,对于 executemany
,它仅报告上次操作的计数。
这演示了一个重要的限制:rowcount
不会累积单个执行调用中多个操作的计数。
带有 SELECT 语句的 rowcount
此示例演示了 rowcount
在 SELECT 语句中的行为。
import sqlite3 with sqlite3.connect('example.db') as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS cities (id INTEGER PRIMARY KEY, name TEXT, population INTEGER)''') cursor.executemany("INSERT INTO cities (name, population) VALUES (?, ?)", [('New York', 8500000), ('London', 9000000)]) # SELECT operation cursor.execute("SELECT * FROM cities WHERE population > 8000000") print(f"Rowcount after SELECT: {cursor.rowcount}") # Output: -1 # Verify actual row count rows = cursor.fetchall() print(f"Actual rows returned: {len(rows)}") # Output: 2
该示例表明 rowcount
对于 SELECT 语句返回 -1。要获得实际计数,您必须获取行并检查长度。
这是 SQLite 中 rowcount
的一个关键限制 - 它不适用于 SELECT 语句,就像您可能从其他数据库系统中期望的那样。
带有事务的 rowcount
此示例演示了 rowcount
在事务中的行为。
import sqlite3 with sqlite3.connect('example.db') as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY, balance INTEGER)''') cursor.executemany("INSERT INTO accounts (balance) VALUES (?)", [(1000,), (500,)]) # Start transaction cursor.execute("BEGIN") cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1") print(f"First update rowcount: {cursor.rowcount}") # Output: 1 cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2") print(f"Second update rowcount: {cursor.rowcount}") # Output: 1 # Rollback transaction conn.rollback() cursor.execute("SELECT balance FROM accounts WHERE id = 1") print(f"Balance after rollback: {cursor.fetchone()[0]}") # Output: 1000
该示例表明 rowcount
在事务中正常工作,报告每个操作受影响的行数。 回滚演示了 rowcount
值不受事务状态的影响。
即使更改被回滚,rowcount
值仍然正确反映了尝试的操作。
带有多个游标的 rowcount
此示例显示了 rowcount
在多个游标中的行为。
import sqlite3 with sqlite3.connect('example.db') as conn: # Create and populate table conn.execute('''CREATE TABLE IF NOT EXISTS inventory (id INTEGER PRIMARY KEY, item TEXT, stock INTEGER)''') conn.execute("INSERT INTO inventory (item, stock) VALUES ('Widget', 50)") # First cursor cursor1 = conn.cursor() cursor1.execute("UPDATE inventory SET stock = stock - 10 WHERE item = 'Widget'") print(f"Cursor1 rowcount: {cursor1.rowcount}") # Output: 1 # Second cursor cursor2 = conn.cursor() cursor2.execute("UPDATE inventory SET stock = stock - 5 WHERE item = 'Widget'") print(f"Cursor2 rowcount: {cursor2.rowcount}") # Output: 1 # Verify final state cursor1.execute("SELECT stock FROM inventory WHERE item = 'Widget'") print(f"Final stock: {cursor1.fetchone()[0]}") # Output: 35
每个游标维护自己的 rowcount
值,仅反映其最近的操作。该示例显示了通过不同游标进行的两个单独的更新。
上下文管理器确保在关闭连接时正确关闭所有游标,防止资源泄漏。
带有条件更新的 rowcount
此示例演示了 rowcount
在可能影响零行的条件更新中的用法。
import sqlite3 with sqlite3.connect('example.db') as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS employees (id INTEGER PRIMARY KEY, name TEXT, salary INTEGER)''') cursor.executemany("INSERT INTO employees (name, salary) VALUES (?, ?)", [('John', 50000), ('Sarah', 60000)]) # Update that affects rows cursor.execute("UPDATE employees SET salary = salary + 5000 WHERE salary < 55000") print(f"Rows updated (condition matched): {cursor.rowcount}") # Output: 1 # Update that affects no rows cursor.execute("UPDATE employees SET salary = salary + 1000 WHERE name = 'Nonexistent'") print(f"Rows updated (no match): {cursor.rowcount}") # Output: 0
第一个 UPDATE 影响 John 的记录(工资 < 55000),因此 rowcount
返回 1。 第二个 UPDATE 不影响任何记录,因此返回 0。
此行为对于确定您的条件操作是否实际修改了数据库中的任何数据非常有用。
最佳实践
- 了解局限性: rowcount 不适用于 SELECT
- 操作后检查: 在 UPDATE/DELETE 之后验证 rowcount
- 使用事务: 与事务结合使用以确保数据完整性
- 关闭资源: 始终使用上下文管理器进行清理
- 考虑替代方案: 对于 SELECT,使用 len(cursor.fetchall())
资料来源
作者
列出所有 Python 教程。