如果我使用带有 pyodbc 游标的上下文管理器,它会在出现错误时回滚吗?
If I use a context manager with a pyodbc cursor, will it rollback on an error?
我尝试阅读 pyodbc 源代码,但它全是 C++ 代码(我不擅长 C++)。我需要知道如下语句的行为:
with connection.cursor() as cursor:
cursor.execute(query_1) #inserts some stuff into table A
cursor.execute(query_2) #inserts some stuff into table B, but throws an error
with connection.cursor() as cursor2:
cursor.execute(select_query_1) #selects from table A
cursor.execute(select_query_2) #selects from table B
这与我们尚未提交的连接相同 - 我很好奇从 table A 中选择是否会给出插入第一个游标的新值 - 或者 [= 中的错误是否15=] 导致第一个游标的工作回滚 table A.
查看 source, and the ODBC Documentation 行为部分取决于 autocommit
是启用还是禁用。
- 如果
autocommit
为 False
,则对 cursor.execute()
的第一次调用隐含地打开一个新事务。 (请参阅注释 1)此游标对 execute()
的每个后续调用都使用相同的事务,除非调用 commit()
或 rollback()
。
- 当 Python 离开
with
块并调用 __exit__
时:
- 如果
autocommit
是False
,并且没有错误,游标会自动提交事务。此操作的来源见注释2。
- 如果
autocommit
为True
,或者出现错误,则游标退出而不结束事务。
- 当使用
cursor.close()
或显式或隐式调用 __del__
关闭游标时,释放游标的内部句柄时,挂起的语句结果也会自动删除。 (注3)
如果cursor.execute()
失败,事务仍处于打开状态,但未提交。在这种情况下,由您决定是提交还是回滚。
尽管如此,您仍然应该在目标环境中测试行为。不同的ODBC数据源有不同级别的事务支持。
注1:(source)
If the data source is in manual-commit mode (requiring explicit transaction initiation) and a transaction has not already been initiated, the driver initiates a transaction before it sends the SQL statement.
// If an error has occurred, `args` will be a tuple of 3 values.
// Otherwise it will be a tuple of 3 `None`s.
I(PyTuple_Check(args));
if (cursor->cnxn->nAutoCommit == SQL_AUTOCOMMIT_OFF && PyTuple_GetItem(args, 0) == Py_None)
...
ret = SQLEndTran(SQL_HANDLE_DBC, cursor->cnxn->hdbc, SQL_COMMIT);
注3:(source
When an application calls SQLFreeHandle to free a statement that has pending results, the pending results are deleted.
pyodbc 不会自动为您处理事务。
这意味着即使 query_2 失败,select_query_1 也会看到由 query_1 插入的记录。 (我假设 try/catch 在第一个代码块周围,所以第二个代码块将被执行)。
但是,某些 RDBMS,即 PostgreSQL,如果同一事务中的先前语句之一失败,则不允许执行任何其他语句(回滚除外)。对于 PostrgreSQL RDBMS(例如)且没有自动提交,如果 query_2 失败,select_query_1 将失败。
根据我使用 pyodbc 连接(使用 Microsoft Access 驱动程序)的经验:
假设自动提交是False
(这似乎是默认的)
不提交:
with pyodbc.connect(connectionString) as con:
with con.cursor() as cursor:
cursor.execute(query)
raise Exception('failed')
是否提交:
with pyodbc.connect(connectionString) as con:
with con.cursor() as cursor:
cursor.execute(query)
raise Exception('failed')
不提交:
with pyodbc.connect(connectionString) as con:
cursor = con.cursor()
cursor.execute(query)
cursor.close()
raise Exception('failed')
是否提交:
with pyodbc.connect(connectionString) as con:
cursor = con.cursor()
cursor.execute(query)
cursor.close()
raise Exception('failed')
我尝试阅读 pyodbc 源代码,但它全是 C++ 代码(我不擅长 C++)。我需要知道如下语句的行为:
with connection.cursor() as cursor:
cursor.execute(query_1) #inserts some stuff into table A
cursor.execute(query_2) #inserts some stuff into table B, but throws an error
with connection.cursor() as cursor2:
cursor.execute(select_query_1) #selects from table A
cursor.execute(select_query_2) #selects from table B
这与我们尚未提交的连接相同 - 我很好奇从 table A 中选择是否会给出插入第一个游标的新值 - 或者 [= 中的错误是否15=] 导致第一个游标的工作回滚 table A.
查看 source, and the ODBC Documentation 行为部分取决于 autocommit
是启用还是禁用。
- 如果
autocommit
为False
,则对cursor.execute()
的第一次调用隐含地打开一个新事务。 (请参阅注释 1)此游标对execute()
的每个后续调用都使用相同的事务,除非调用commit()
或rollback()
。 - 当 Python 离开
with
块并调用__exit__
时:- 如果
autocommit
是False
,并且没有错误,游标会自动提交事务。此操作的来源见注释2。 - 如果
autocommit
为True
,或者出现错误,则游标退出而不结束事务。
- 如果
- 当使用
cursor.close()
或显式或隐式调用__del__
关闭游标时,释放游标的内部句柄时,挂起的语句结果也会自动删除。 (注3)
如果cursor.execute()
失败,事务仍处于打开状态,但未提交。在这种情况下,由您决定是提交还是回滚。
尽管如此,您仍然应该在目标环境中测试行为。不同的ODBC数据源有不同级别的事务支持。
注1:(source)
If the data source is in manual-commit mode (requiring explicit transaction initiation) and a transaction has not already been initiated, the driver initiates a transaction before it sends the SQL statement.
// If an error has occurred, `args` will be a tuple of 3 values.
// Otherwise it will be a tuple of 3 `None`s.
I(PyTuple_Check(args));
if (cursor->cnxn->nAutoCommit == SQL_AUTOCOMMIT_OFF && PyTuple_GetItem(args, 0) == Py_None)
...
ret = SQLEndTran(SQL_HANDLE_DBC, cursor->cnxn->hdbc, SQL_COMMIT);
注3:(source
When an application calls SQLFreeHandle to free a statement that has pending results, the pending results are deleted.
pyodbc 不会自动为您处理事务。
这意味着即使 query_2 失败,select_query_1 也会看到由 query_1 插入的记录。 (我假设 try/catch 在第一个代码块周围,所以第二个代码块将被执行)。 但是,某些 RDBMS,即 PostgreSQL,如果同一事务中的先前语句之一失败,则不允许执行任何其他语句(回滚除外)。对于 PostrgreSQL RDBMS(例如)且没有自动提交,如果 query_2 失败,select_query_1 将失败。
根据我使用 pyodbc 连接(使用 Microsoft Access 驱动程序)的经验:
假设自动提交是False
(这似乎是默认的)
不提交:
with pyodbc.connect(connectionString) as con:
with con.cursor() as cursor:
cursor.execute(query)
raise Exception('failed')
是否提交:
with pyodbc.connect(connectionString) as con:
with con.cursor() as cursor:
cursor.execute(query)
raise Exception('failed')
不提交:
with pyodbc.connect(connectionString) as con:
cursor = con.cursor()
cursor.execute(query)
cursor.close()
raise Exception('failed')
是否提交:
with pyodbc.connect(connectionString) as con:
cursor = con.cursor()
cursor.execute(query)
cursor.close()
raise Exception('failed')