sqlite SQL:在SELECT之后插入时关闭此连接

iqjalb3h  于 2022-11-15  发布在  SQLite
关注(0)|答案(2)|浏览(156)

我从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()

当我的代码执行INSERT行时,我收到以下错误:

sqlalchemy.exc.ResourceClosedError: This Connection is closed

但是,如果我将RES转换为如下所示的列表:

res = list(engine.execute(sel))

我的代码运行得很好。这里发生了什么事?

lh80um4z

lh80um4z1#

SQLAlChemy有两个必须了解的概念:连接和引擎。一个引擎可以支持多个同时连接。在您的示例中,您将表绑定到一个引擎。现在,每当您调用.execute时,都会为您执行的每个查询创建一个新连接。但是,Sqlite3只允许1个并发的“连接”。
解决此问题的最佳方法是创建连接并显式使用它,而不是引擎自动创建的连接;并将该连接与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等也可以很好地处理这一点)。

bybem2ql

bybem2ql2#

对于我来说,当我尝试发布表的条目时,我收到了这个错误,我使用的是sqlachmey的新语法,我在使用select时忘记了添加表类名称,所以我写成了select().where...而不是select(tbaleNameClass).where...,所以我得到了这个ResourceClosedError

sqlalchemy.exc.ResourceClosedError: This result object does not return rows. It has been closed automatically.

所以我唯一要做的就是正确地写出语法,而不是写成

query = select().where(
        Assessment.created_by == assessment.created_by)

query = select(Assessment).where(
        Assessment.created_by == assessment.created_by)

Assessment是表类名称
因此,如果你们中的任何人首先得到相同的错误检查,那么您写的东西是正确的:)。

相关问题