我想将一些代码移植到使用sqlite数据库的Python,并且我试图让事务工作,并且我变得非常困惑。我真的很困惑,我在其他语言中使用过很多sqlite,因为它很棒,但我根本无法弄清楚这里有什么问题。与Python的交易sqlite3
这里是我的测试数据库(被馈送到sqlite3命令行工具)的模式。
BEGIN TRANSACTION;
CREATE TABLE test (i integer);
INSERT INTO "test" VALUES(99);
COMMIT;
这是一个测试程序。
import sqlite3
sql = sqlite3.connect("test.db")
with sql:
c = sql.cursor()
c.executescript("""
update test set i = 1;
fnord;
update test set i = 0;
""")
您可能会注意到它的故意错误。这会导致SQL脚本在更新执行后的第二行失败。
根据文档,with sql
语句应该设置一个隐含的内容事务,只有在块成功时才会提交。但是,当我运行它时,我得到了预期的SQL错误...但是i的值从99设置为1.我期望它保持在99,因为第一次更新应该回滚。
这是另一个测试程序,它明确地呼叫commit()
和rollback()
。
import sqlite3
sql = sqlite3.connect("test.db")
try:
c = sql.cursor()
c.executescript("""
update test set i = 1;
fnord;
update test set i = 0;
""")
sql.commit()
except sql.Error:
print("failed!")
sql.rollback()
这表现在完全相同的方式---我会从99变到1
现在我打电话BEGIN和明确承诺:
import sqlite3
sql = sqlite3.connect("test.db")
try:
c = sql.cursor()
c.execute("begin")
c.executescript("""
update test set i = 1;
fnord;
update test set i = 0;
""")
c.execute("commit")
except sql.Error:
print("failed!")
c.execute("rollback")
这也失败,但以不同的方式。我得到这个:
sqlite3.OperationalError: cannot rollback - no transaction is active
但是,如果我更换到c.execute()
来电来c.executescript()
,那么它工作(我仍为99)!
(我还要补充一点,如果我把begin
和commit
内调用内部executescript
那么它在所有情况下都正确的行为,但遗憾的是我不能用我的应用程序的方法。此外,改变sql.isolation_level
出现对行为没有影响。)
有人可以向我解释发生了什么吗?我需要明白这一点;如果我不能在数据库中信任的交易,我不能让我的应用程序的工作...
的Python 2.7,蟒蛇-sqlite3的2.6.0,sqlite3的3.7.13,Debian的。
谢谢你,apsw正是我要找的。尽管如此,我仍然感到困惑。如果python-sqlite3的事务处理被破坏,为什么没有人注意到并修复它,因为它似乎是Python的默认Sqlite绑定?交易是否是任何SQL库的核心竞争力? – 2013-04-09 11:04:01
它是破解的* Python * API;并且出于向后兼容性的原因它不能轻易改变。 – 2013-04-09 16:27:23
那么,我的问题仍然存在---为什么Python API会这样做? – 2013-04-09 22:39:24