【发布时间】:2013-03-29 05:29:45
【问题描述】:
我正在尝试将一些代码移植到使用 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() 的调用替换为 c.executescript(),那么它有效(我仍然保持在 99)!
(我还应该补充一点,如果我将 begin 和 commit 放在对 executescript 的内部调用中,那么它在所有情况下都表现正确,但不幸的是我不能在我的应用程序中使用这种方法。在此外,更改 sql.isolation_level 似乎对行为没有影响。)
有人可以向我解释这里发生了什么吗?我需要了解这一点;如果我不能信任数据库中的事务,我就无法让我的应用程序工作......
Python 2.7、python-sqlite3 2.6.0、sqlite3 3.7.13、Debian。
【问题讨论】:
标签: python-2.7 sqlite python-db-api