18

我在某处读到,要在 Python 中将数据保存到 SQLite3 数据库,commit应该调用连接对象的方法。然而我从来不需要这样做。为什么?

4

5 回答 5

25

这意味着您的 SQLite3 数据库驱动程序以自动提交模式运行

提交模式

数据库事务是一个恢复单元。在事务数据库引擎中,所有SQL 语句都在一个数据库事务中执行。

  • 当一条 SQL 语句未包含在一对开始事务(BEGINSAVEPOINT)和结束事务(COMMITROLLBACK) SQL 语句中时,它将在由 SQL 语句边界隐式分隔RELEASE的数据库事务中执行。据说 SQL 语句处于自动提交模式,因为它的数据库事务是自动分隔的。

  • 当一条 SQL 语句包含在一对开始事务 ( BEGINor SAVEPOINT) 和结束事务 ( COMMIT, ROLLBACKor RELEASE) SQL 语句中时,它将在由这对 SQL 语句明确分隔的数据库事务中执行。据说 SQL 语句处于手动提交模式,因为它的数据库事务是手动分隔的。

换句话说,在数据库引擎级别,自动提交模式是默认的。

最佳实践是始终使用手动提交模式,因为通过将 SQL 语句显式分组到数据库事务中,可以避免数据损坏,因为恢复单元是按预期分隔的。

数据库驱动程序位于数据库引擎之上,因此可以转换它们发送到底层数据库引擎的 SQL 语句。数据库驱动程序通常通过任何BEGIN连接和结束事务(COMMITROLLBACK)SQL 语句(也就是说,在任何尚未在数据库事务)。这样,喜欢使用自动提交模式的用户必须明确告诉数据库驱动程序。

换句话说,在数据库驱动程序级别,手动提交模式通常是默认的。

SQLite 数据库引擎

SQLite 数据库引擎默认以自动提交模式运行:

测试自动提交模式

int sqlite3_get_autocommit(sqlite3*);

如果给定的sqlite3_get_autocommit()数据库连接处于或不处于自动提交模式,则接口分别返回非零或零。自动提交模式默认开启。BEGIN语句禁用自动提交模式。自动提交模式由 aCOMMIT或重新启用ROLLBACK

如果在多语句事务中的语句上发生某些类型的错误(错误包括SQLITE_FULLSQLITE_IOERRSQLITE_NOMEMSQLITE_BUSYSQLITE_INTERRUPT),则事务可能会自动回滚。判断 SQLite 是否在出错后自动回滚事务的唯一方法就是使用这个函数。

如果在该例程运行时另一个线程更改了数据库连接的自动提交状态,则返回值未定义。

另请参阅对象、常量和函数的列表。

SQLite3 数据库驱动

PEP 249要求 Python 数据库驱动程序默认以手动提交模式运行:

.commit()

将任何挂起的事务提交到数据库。

请注意,如果数据库支持自动提交功能,则最初必须关闭。可以提供一个接口方法来重新打开它。

不支持事务的数据库模块应该使用 void 功能实现此方法。

因此,SQLite3 数据库驱动程序默认以手动提交模式运行:

控制交易

默认情况下,底层sqlite3库以自动提交模式运行,但 Pythonsqlite3模块默认情况下不会。

autocommitmode 表示修改数据库的语句立即生效。BEGINorSAVEPOINT语句禁用autocommit模式,结束最外层事务的a COMMIT、 aROLLBACK或 a将重新打开模式。RELEASEautocommit

默认情况下,Pythonsqlite3模块BEGIN会在数据修改语言 (DML) 语句(即 INSERT/ UPDATE/ DELETE/ REPLACE)之前隐式发出语句。

您可以通过调用的参数或连接的属性来控制隐式执行哪种BEGIN语句。如果您指定 no ,则使用纯文本,这等效于指定。其他可能的值为和 。sqlite3isolation_levelconnect()isolation_levelisolation_levelBEGINDEFERREDIMMEDIATEEXCLUSIVE

您可以通过设置来禁用sqlite3模块的隐式事务管理。这将使底层库在模式下运行。然后,您可以通过在代码中显式发出、、和语句来完全控制事务状态。isolation_levelNonesqlite3autocommitBEGINROLLBACKSAVEPOINTRELEASE

在 3.6 版更改: sqlite3用于在 DDL 语句之前隐式提交打开的事务。这已不再是这种情况。

笔记。— 出于向后兼容的原因,SQLite3 数据库驱动程序仅在数据修改INSERT、或)SQL 语句之前启动手动提交模式UPDATE,而不是在数据定义(、)或数据查询()SQL 语句之前,这不符合 PEP 249并将希望很快得到解决DELETEREPLACECREATEDROPSELECT

例子

以下 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,因为在关闭连接时会删除内存数据库。

于 2018-01-22T22:51:01.820 回答
4

可能自动提交已打开,默认为http://www.sqlite.org/c3ref/get_autocommit.html

于 2011-01-15T12:41:47.137 回答
3

添加isolation_level=None到连接(参考

db = sqlite.connect(":memory:", isolation_level=None)
于 2014-05-13T02:45:59.773 回答
3

Python sqlite3 在“INSERT”或“UPDATE”之前自动发出 BEGIN 语句。之后,它会自动提交任何其他命令或 db.close()

于 2013-04-12T09:34:15.280 回答
3

连接对象也可以用作自动提交或回滚事务的上下文管理器。11.13.7.3。在 docs.python 上

# Successful, con.commit() is called automatically afterwards
with con:
    con.execute("insert into person(firstname) values (?)", ("Joe",))
于 2011-01-15T12:47:44.197 回答