改变底层数据库时sqlite游标不一致的行为

sqlite cursor inconsistent behaviour when altering underlying database

我无法理解 python 的 sqlite3 模块的游标对象的行为。据我了解,游标对象的行为类似于在数据结构上保留 "view" 的迭代器。现在,我认为这有两种行为方式:

1) 执行时,匹配 SELECT * 语句的数据库状态与未来变化保持分离

2) 执行时,与SELECT * 语句匹配的数据库状态只是底层可变数据的视图。 IE。一旦 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')

平台

不幸的是,这是 SQLite 的工作方式。来自 Isolation In SQLite:

... But what about changes that occur while the SELECT statement is running? What if a SELECT statement is started and the sqlite3_step() interface steps through roughly half of its output, then some UPDATE statements are run by the application that modify the table that the SELECT statement is reading, then more calls to sqlite3_step() are made to finish out the SELECT statement? Will the later steps of the SELECT statement see the changes made by the UPDATE or not? The answer is that this behavior is undefined... And hence, developers should diligently avoid writing applications that make assumptions about what will occur in that circumstance.

这意味着 SQLite 可以在同一个数据库的不同连接之间提供一些隔离(注意,应该只写一个),但是你不应该尝试修改数据库,至少 table(s)正在阅读,在 SELECT.

的开头和结尾之间