根据文档,
连接对象可用作自动提交或回滚事务的上下文管理器。发生异常时,事务回滚;否则,事务被提交:
我知道with
语句中的所有内容都应该是原子事务。现在考虑这个代码
import sqlite3
con = sqlite3.connect(':memory:')
try:
with con:
con.execute('create table foo (id integer primary key)')
con.execute('insert into foo values (1)')
con.execute('insert into foo values (1)')
except sqlite3.Error:
print('transaction failed')
try:
rec = con.execute('select count(*) from foo')
print('number of records: {}'.format(rec.fetchone()[0]))
except sqlite3.Error as e:
print(e)
Run Code Online (Sandbox Code Playgroud)
返回
import sqlite3
con = sqlite3.connect(':memory:')
try:
with con:
con.execute('create table foo (id integer primary key)')
con.execute('insert into foo values (1)')
con.execute('insert into foo values (1)')
except sqlite3.Error:
print('transaction failed')
try:
rec = con.execute('select count(*) from foo')
print('number of records: {}'.format(rec.fetchone()[0]))
except sqlite3.Error as e:
print(e)
Run Code Online (Sandbox Code Playgroud)
一方面,由于重复值,交易失败。另一方面,表foo
存在,即使它是空的,这意味着第一个插入已回滚。表创建不应该也回滚吗?
“手动”进行交易会产生预期的结果:
import sqlite3
con = sqlite3.connect(':memory:')
con.execute('begin')
try:
con.execute('create table foo (id integer primary key)')
con.execute('insert into foo values (1)')
con.execute('insert into foo values (1)')
con.execute('commit')
except sqlite3.Error:
con.execute('rollback')
print('transaction failed')
try:
rec = con.execute('select count(*) from foo')
print('number of records: {}'.format(rec.fetchone()[0]))
except sqlite3.Error as e:
print(e)
Run Code Online (Sandbox Code Playgroud)
返回
transaction failed
number of records: 0
Run Code Online (Sandbox Code Playgroud)
为什么会出现差异?
从 Python 3.6 开始,DDL 或数据定义语言语句(如CREATE TABLE
)不会启动事务。这意味着任何此类语句都会在您执行时自动提交。
请参阅控制交易部分:
默认情况下,
sqlite3
模块打开交易数据修改语言(DML)语句之前隐式(即INSERT
/UPDATE
/DELETE
/REPLACE
)。[...]
在 3.6 版更改:
sqlite3
用于在 DDL 语句之前隐式提交打开的事务。这已不再是这种情况。
这意味着如果您希望 DDL 语句成为事务的一部分,则必须显式启动事务。
使用连接作为上下文管理器仍然只在退出时发出提交或回滚,它不会启动事务;相反,遇到的第一个 DML 语句将启动一个。如果您希望 DDL 成为事务的一部分,请begin
在顶部添加一条语句:
try:
with con:
con.execute('begin') # explicit, rather than implicit, transaction start
con.execute('create table foo (id integer primary key)')
con.execute('insert into foo values (1)')
con.execute('insert into foo values (1)')
except sqlite3.Error:
print('transaction failed')
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
695 次 |
最近记录: |