我很难理解python sqlite3模块的游标对象的行为。据我了解,游标对象的行为就像一个迭代器,在数据结构上保持“视图”。现在,我认为这种行为有两种方式:
1)执行后,与SELECT *
语句匹配的数据库的状态与期货更改保持隔离
2)执行后,与SELECT *
语句匹配的数据库的状态只是基础可变数据的视图。即一旦执行for ... in cur
行,就会进行惰性评估。
但显然不是这样,请参见下面的脚本和输出。当执行此脚本时,为什么UPDATE
命令没有合并到光标中,而INSERT
是为什么?始终使用result = list(cur.execute(...))
会更好吗?
#!/usr/bin/env python3
import sqlite3
con = sqlite3.connect("db.sqlite")
con.execute("""CREATE TABLE IF NOT EXISTS `table` (
`id` INTEGER UNIQUE,
`name` TEXT,
PRIMARY KEY(`id`)
);""")
con.execute("INSERT INTO `table` VALUES (1, 'smith')")
con.execute("INSERT INTO `table` VALUES (2, 'mia')")
con.commit()
print("in db: (1, smith), (2, mia)")
### Querying the table
cur = con.cursor()
cur.execute("SELECT * FROM `table`")
### Changing the table
print("altering table: add (3, kim), change (1, smith) to (1, james)")
con.execute("UPDATE `table` SET name='james' where id=1")
con.execute("INSERT INTO `table` VALUES (3, 'kim')")
con.commit()
print()
print("1) expect immutable: (1, smith), (2, mia)")
print("2) expect mutable: (1, james), (2, mia), (3, kim)")
print()
print("But got: ")
for row in cur: print(row)
输出
in db: (1, smith), (2, mia)
altering table: add (3, kim), change (1, smith) to (1, james)
1) expect immutable: (1, smith), (2, mia)
2) expect mutable: (1, james), (2, mia), (3, kim)
But got:
(1, 'smith')
(2, 'mia')
(3, 'kim')
平台
答案 0 :(得分:1)
不幸的是,这是SQLite的工作方式。来自Isolation In SQLite:
...但是,在SELECT语句运行时发生的更改又如何呢?如果启动了SELECT语句,并且sqlite3_step()接口大致遍历了其输出的一半,那么应用程序会运行一些UPDATE语句,修改该SELECT语句正在读取的表,然后对sqlite3_step()进行更多调用完成SELECT语句? SELECT语句的后续步骤是否会看到UPDATE所做的更改?答案是这种行为是不确定的...因此,开发人员应勤奋避免编写可能会在这种情况下进行假设的应用程序。
这意味着SQLite可以在同一个数据库的不同连接之间提供某种隔离(请注意,只有一个应该写),但是在开始之间,您不应尝试修改数据库,至少要读取正在读取的表。以及SELECT的结尾。