我正在尝试将一些代码移植到使用 sqlite 数据库的 Python,并且我正在尝试让事务正常工作,但我真的很困惑。我对此感到非常困惑;我在其他语言中使用过很多 sqlite,因为它很棒,但我根本无法弄清楚这里有什么问题。
这是我的测试数据库的架构(要输入 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()
其行为方式完全相同 --- i 从 99 变为 1。
现在我明确地调用 BEGIN 和 COMMIT :
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()
但是,如果我替换对to的调用c.executescript()
,那么它可以工作(我保持在 99)!
(我还应该补充一点,如果我将begin
andcommit
放在内部调用中,executescript
那么它在所有情况下都会正确运行,但不幸的是我不能在我的应用程序中使用这种方法。此外,更改sql.isolation_level
似乎对行为没有任何影响。 )
有人可以向我解释这里发生了什么吗?我需要了解这一点;如果我不能信任数据库中的事务,我就不能让我的应用程序工作......
Python 2.7、python-sqlite3 2.6.0、sqlite3 3.7.13、Debian。