我想將一些代碼移植到使用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