簡體   English   中英

為什么 SQLite3 不需要 commit() 調用來保存數據?

[英]Why doesn’t SQLite3 require a commit() call to save data?

我在某處讀到要將數據保存到 Python 中的 SQLite3 數據庫,應該調用連接對象的方法commit 然而,我從來不需要這樣做。 為什么?

這意味着您的 SQLite3 數據庫驅動程序在自動提交模式下運行

提交模式

數據庫事務是一個恢復單元。 在事務數據庫引擎中所有SQL 語句都在一個數據庫事務中執行。

  • 當 SQL 語句沒有包含在一對開始事務( BEGINSAVEPOINT )和結束事務( COMMITROLLBACKRELEASE )SQL 語句中時,它將在由 SQL 語句的邊界隱式分隔的數據庫事務中執行。 據說 SQL 語句處於自動提交模式,因為它的數據庫事務是自動分隔的。

  • 當 SQL 語句包含在一對開始事務( BEGINSAVEPOINT )和結束事務( COMMITROLLBACKRELEASE )SQL 語句中時,它將在由這對 SQL 語句顯式分隔的數據庫事務中執行。 據說 SQL 語句處於手動提交模式,因為它的數據庫事務是手動分隔的。

換句話說,在數據庫引擎級別,自動提交模式是默認的。

最佳實踐是始終使用手動提交模式,因為通過將 SQL 語句顯式地分組到數據庫事務中,可以避免數據損壞,因為恢復單元按預期分隔。

數據庫驅動程序高於數據庫引擎,因此可以轉換它們發送到底層數據庫引擎的 SQL 語句。 數據庫驅動程序通常通過在任何連接和結束事務( COMMITROLLBACK )SQL 語句之后(即在任何 SQL 語句之前)向數據庫引擎隱式發送開始事務( BEGIN )SQL 語句來強制執行手動提交模式。尚未在數據庫事務中)。 這樣,喜歡使用自動提交模式的用戶必須明確告訴數據庫驅動程序。

換句話說,在數據庫驅動程序級別,手動提交模式通常是默認的。

SQLite 數據庫引擎

SQLite 數據庫引擎默認在自動提交模式下運行:

測試自動提交模式

int sqlite3_get_autocommit(sqlite3*);

如果給定的數據庫連接是否處於自動提交模式, sqlite3_get_autocommit()接口分別返回非零或零。 自動提交模式默認開啟。 自動提交模式由BEGIN語句禁用。 自動提交模式由COMMITROLLBACK重新啟用。

如果在多語句事務中的語句上發生某些類型的錯誤(錯誤包括SQLITE_FULLSQLITE_IOERRSQLITE_NOMEMSQLITE_BUSYSQLITE_INTERRUPT ),則事務可能會自動回滾。 查明SQLite是否在出錯后自動回滾事務的唯一方法就是使用這個函數。

如果另一個線程在此例程運行時更改了數據庫連接的自動提交狀態,則返回值未定義。

另請參閱對象、常量和函數列表。

SQLite3 數據庫驅動程序

PEP 249要求 Python 數據庫驅動程序默認在手動提交模式下運行:

.commit()

將任何掛起的事務提交到數據庫。

請注意,如果數據庫支持自動提交功能,則最初必須關閉此功能。 可以提供接口方法來將其重新打開。

不支持事務的數據庫模塊應使用 void 功能實現此方法。

因此, SQLite3 數據庫驅動程序默認在手動提交模式下運行:

控制交易

底層的sqlite3庫默認以自動提交模式運行,但 Python sqlite3模塊默認不運行。

autocommit模式意味着修改數據庫的語句立即生效。 BEGINSAVEPOINT語句禁用autocommit模式,結束最外層事務的COMMITROLLBACKRELEASE重新打開autocommit模式。

默認情況下,Python sqlite3模塊在數據修改語言 (DML) 語句(即INSERT / UPDATE / DELETE / REPLACE )之前隱式發出BEGIN語句。

您可以通過connect()調用的isolation_level參數或連接的isolation_level屬性來控制sqlite3隱式執行哪種BEGIN語句。 如果您未指定isolation_level ,則使用普通BEGIN ,這等效於指定DEFERRED 其他可能的值是IMMEDIATEEXCLUSIVE

您可以通過將isolation_level設置為None來禁用sqlite3模塊的隱式事務管理。 這將使底層的sqlite3庫在autocommit模式下運行。 然后,您可以通過在代碼中顯式發出BEGINROLLBACKSAVEPOINTRELEASE語句來完全控制事務狀態。

在 3.6 版更改: sqlite3用於在 DDL 語句之前隱式提交打開的事務。 這已不再是這種情況。

筆記。 — 出於向后兼容的原因,SQLite3 數據庫驅動程序僅在數據修改INSERTUPDATEDELETEREPLACE )SQL 語句之前啟動手動提交模式,而不是在數據定義CREATEDROP )或數據查詢SELECT )SQL 語句之前啟動不符合 PEP 249,有望很快得到解決

例子

以下 Python 程序說明了對 SQLite3 數據庫驅動程序使用手動提交模式與自動提交模式的含義:

import sqlite3

# Manual commit mode (the default).

connection = sqlite3.connect("test.sqlite")
cursor = connection.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS t (i INT)")  # sent as is (DDL)
cursor.execute("INSERT INTO t VALUES (?)", (5,))  # sent as BEGIN; … (DML)
cursor.close()
connection.close()  # connection closed without COMMIT statement (common error)

connection = sqlite3.connect("test.sqlite")
cursor = connection.cursor()
cursor.execute("SELECT * FROM t")  # table persisted (full transaction)
assert cursor.fetchall() == []  # data did not persist (partial transaction)
cursor.close()
connection.close()

# Auto-commit mode.

connection = sqlite3.connect("test.sqlite", isolation_level=None)
cursor = connection.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS t (i INT)")  # sent as is
cursor.execute("INSERT INTO t VALUES (?)", (5,))  # sent as is
cursor.close()
connection.close()

connection = sqlite3.connect("test.sqlite", isolation_level=None)
cursor = connection.cursor()
cursor.execute("SELECT * FROM t")  # table persisted
assert cursor.fetchall() == [(5,)]  # data persisted
cursor.close()
connection.close()

筆記。 — 如果使用內存數據庫而不是磁盤數據庫(通過將參數":memory:"而不是"test.sqlite"傳遞給函數sqlite3.connect ),則第二個斷言將失敗,因為在內存中當連接關閉時,數據庫將被刪除。

Python sqlite3 在“插入”或“更新”之前自動發出 BEGIN 語句。 之后它會自動提交任何其他命令或 db.close()

添加isolation_level=None連接( Ref

db = sqlite.connect(":memory:", isolation_level=None)

可能自動提交已開啟,默認情況下為http://www.sqlite.org/c3ref/get_autocommit.html

連接對象也可以用作自動提交或回滾事務的上下文管理器。 11.13.7.3。 在 docs.python 上

# Successful, con.commit() is called automatically afterwards
with con:
    con.execute("insert into person(firstname) values (?)", ("Joe",))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM