更改基础数据库时,sqlite游标的行为不一致

时间:2019-03-01 14:20:56

标签: python sqlite database-cursor

我很难理解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')

平台

  • Ubuntu 18.10 x64
  • Python 3.6.7(默认,2018年10月22日,11:32:17)
  • sqlite3.version ='2.6.0'

1 个答案:

答案 0 :(得分:1)

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

  

...但是,在SELECT语句运行时发生的更改又如何呢?如果启动了SELECT语句,并且sqlite3_step()接口大致遍历了其输出的一半,那么应用程序会运行一些UPDATE语句,修改该SELECT语句正在读取的表,然后对sqlite3_step()进行更多调用完成SELECT语句? SELECT语句的后续步骤是否会看到UPDATE所做的更改?答案是这种行为是不确定的...因此,开发人员应勤奋避免编写可能会在这种情况下进行假设的应用程序。

这意味着SQLite可以在同一个数据库的不同连接之间提供某种隔离(请注意,只有一个应该写),但是在开始之间,您不应尝试修改数据库,至少要读取正在读取的表。以及SELECT的结尾。