sqlalchemy.exc.ResourceClosedError: This Connection is closed when inserting after select
sqlalchemy.exc.ResourceClosedError: This Connection is closed when inserting after select
我正在从 SQLite 数据库中执行 select()
然后 insert()
:
engine = create_engine('sqlite:///testdb.db')
metadata = MetaData(bind=engine)
test = Table('test', metadata, autoload=True)
# Select all from pending_data
sel = select([test])
res = engine.execute(sel)
print res
# do an insert into pending_data
test.insert()\
.values(info='blah')\
.execute()
当我的代码执行插入行时,出现此错误:
sqlalchemy.exc.ResourceClosedError: This Connection is closed
但是,如果我将 res 转换成这样的列表:
res = list(engine.execute(sel))
我的代码运行良好。这是怎么回事?
SQLAlchemy 有两个必须了解的概念:连接和引擎。一个引擎可以支持多个并发连接。在您的示例中,您将 table 绑定到引擎。现在,无论何时调用 .execute
,都会为您执行的每个查询创建一个新连接。但是 sqlite3 只允许同时存在 1 个 "connection"。
解决此问题的最佳方法是创建连接并显式使用它,而不是引擎自动创建的连接;并将连接与 with
语句一起使用,这确保连接将在块的末尾关闭:
engine = create_engine('sqlite:///testdb.db')
metadata = MetaData(bind=engine)
test = Table('test', metadata, autoload=True)
with engine.connect() as connection:
# Select all from pending_data
sel = select([test])
res = connection.execute(sel)
# do an insert into pending_data
connection.execute(test.insert().values(info='blah'))
要了解此行为,会发生错误,因为您在隐式创建和保存的集合中持有活动游标(这由 res
变量引用;直到您使用它或关闭它,或删除对它的引用,游标和连接将处于活动状态,并且数据库将被锁定)。
当您执行 list(res)
时,您正在使用游标,它会被 SQLAlchemy 关闭;如果结果的引用计数下降到 0,也会发生同样的情况。
您也可以尝试以下方法来查看要点,它们会按您的预期工作:
res = engine.execute(sel)
print(res)
res.close() # close explicitly
或
res = engine.execute(sel)
print(res)
del res # drop the only reference to res
因此始终完全使用 ResultProxy 或显式关闭它,或者在完成后删除对它的引用。
如果您重复使用相同的 连接,这不是问题;仅当您创建与 sqlite3 数据库的新连接时(postgresql、mysql、oracle 等也可以很好地处理)。
我正在从 SQLite 数据库中执行 select()
然后 insert()
:
engine = create_engine('sqlite:///testdb.db')
metadata = MetaData(bind=engine)
test = Table('test', metadata, autoload=True)
# Select all from pending_data
sel = select([test])
res = engine.execute(sel)
print res
# do an insert into pending_data
test.insert()\
.values(info='blah')\
.execute()
当我的代码执行插入行时,出现此错误:
sqlalchemy.exc.ResourceClosedError: This Connection is closed
但是,如果我将 res 转换成这样的列表:
res = list(engine.execute(sel))
我的代码运行良好。这是怎么回事?
SQLAlchemy 有两个必须了解的概念:连接和引擎。一个引擎可以支持多个并发连接。在您的示例中,您将 table 绑定到引擎。现在,无论何时调用 .execute
,都会为您执行的每个查询创建一个新连接。但是 sqlite3 只允许同时存在 1 个 "connection"。
解决此问题的最佳方法是创建连接并显式使用它,而不是引擎自动创建的连接;并将连接与 with
语句一起使用,这确保连接将在块的末尾关闭:
engine = create_engine('sqlite:///testdb.db')
metadata = MetaData(bind=engine)
test = Table('test', metadata, autoload=True)
with engine.connect() as connection:
# Select all from pending_data
sel = select([test])
res = connection.execute(sel)
# do an insert into pending_data
connection.execute(test.insert().values(info='blah'))
要了解此行为,会发生错误,因为您在隐式创建和保存的集合中持有活动游标(这由 res
变量引用;直到您使用它或关闭它,或删除对它的引用,游标和连接将处于活动状态,并且数据库将被锁定)。
当您执行 list(res)
时,您正在使用游标,它会被 SQLAlchemy 关闭;如果结果的引用计数下降到 0,也会发生同样的情况。
您也可以尝试以下方法来查看要点,它们会按您的预期工作:
res = engine.execute(sel)
print(res)
res.close() # close explicitly
或
res = engine.execute(sel)
print(res)
del res # drop the only reference to res
因此始终完全使用 ResultProxy 或显式关闭它,或者在完成后删除对它的引用。
如果您重复使用相同的 连接,这不是问题;仅当您创建与 sqlite3 数据库的新连接时(postgresql、mysql、oracle 等也可以很好地处理)。