SQLAlchemy ORM没有关闭会话?

3
我有一个周末项目,使用Bottle.py(0.10.11)和SQLAlchemy(0.7.9)作为后端,并使用MySQL。我遇到了很多“MySQL服务器已关闭”的问题,经过排查发现是因为一些会话在夜间未关闭而导致的。现在我知道了MySQL会话未关闭的原因,但我不知道该如何解决。以下是我在web.py页面中的代码。
[...]
db = create_engine('mysql://USER:PASSWORD@DATABASE', poolclass=NullPool)
session = scoped_session(sessionmaker(bind=db))

@route("/")
    links = session.query(Link)

    session.close()
    return bottle.template("index", links=links)

在我看来,index.tpl

[...]
%for link in links:
    <div class="link">
        <a class="link" href="{{link.url}}">{{link.title}}</a> 
        %for tag in link.tags:
            <a href="/tag/{{tag.text}}" class="tag">{{tag.text}}</a>
        %end
        <a href="/edit/{{link.id}}">edit</a>
    </div>
%end
[...]

如果我使用session.query(Link).all()而不是session.query(Link),MySQL会话会正确关闭,但我无法从ORM因素中获益。
如何关闭所有会话?
我做错了什么?
1个回答

7
当你执行q = session.query(Link)时,它是一个未执行的Query对象。你可以正确地调用session.close()方法,但是在把Query对象传递到模板中并遍历它时,会打开一个新的事务在Session上发出SQL语句。
在这种情况下,你要么在关闭Session之前调用all()方法,要么更灵活地保持Session处于打开状态,直到模板完成渲染。然后模板也可以引用惰性加载的属性。

是的,谢谢。我认为这正是发生的事情。如果我调用 all(),我会得到这个错误:Parent instance <Link at 0x7f3c7f8270d0> is not bound to a Session; lazy load operation of attribute 'tags' cannot proceed。在模板渲染后,我应该在哪里关闭会话? - kevin
好的,我解决了。要么在session.query(Link)中添加.options(subqueryload('tags')).all(),要么在关系定义中添加惰性加载relationship("Tag", lazy='joined')并调用session.query(Link).all() - kevin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接