When is session.close required?

4,279 views
Skip to first unread message

Brian Candler

unread,
May 23, 2017, 9:55:39 AM5/23/17
to sqlalchemy
Hello,

I have a question about when "close" should or should not be called on a session.


"When the transactional state is completed after a rollback or commit, the Session releases all Transaction and Connection resources, and goes back to the “begin” state, which will again invoke new Connection and Transaction objects as new requests to emit SQL statements are received."

From this description, given that the session releases its resources, it seems that there's no need to call "close" explicitly on the session, whether or not you want to re-use the session object or not.  There is also some example code, which doesn't invoke session.close().  

session = Session()
try:
    ...
    # commit.  The pending changes above
    # are flushed via flush(), the Transaction
    # is committed, the Connection object closed
    # and discarded, the underlying DBAPI connection
    # returned to the connection pool.
    session.commit()
except:
    # on rollback, the same closure of state
    # as that of commit proceeds.
    session.rollback()
    raise

However, under http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it there's a different example, this time explicitly calling close() on the session:

def run_my_program():
    session = Session()
    try:
        ThingOne().go(session)
        ThingTwo().go(session)

        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

So my question is, what does session.close() do that commit/rollback does not?

It's also not entirely clear to me if a session object can be reused after it has been closed.  At http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.close it says:

"If this session were created with autocommit=False, a new transaction is immediately begun. Note that this new transaction does not use any connection resources until they are first needed."

So it sounds to me like a closed session *can* be re-used.  Is that correct?

Related to this is calling scoped_session.remove.  At http://docs.sqlalchemy.org/en/latest/orm/contextual.html#unitofwork-contextual it says:

                    web request ends  -> # the registry is instructed to
                                         # remove the Session
                                         Session.remove()

As I understand it, this calls "close" on the underlying session *and* removes it from the registry, so you get a fresh Session next time.  However if the framework already does a commit/rollback, why not just allow the registry to retain the same session object?

Thanks,

Brian.

mike bayer

unread,
May 23, 2017, 11:38:57 AM5/23/17
to sqlal...@googlegroups.com
fixed in 7fc7492d86f6e5ca105743a184cd07190e9f9b28 /
f830fff2583b3e23f72fdc3768be22f64e2212d1

https://bitbucket.org/zzzeek/sqlalchemy/commits/7fc7492d86f6


>
> However, under
> http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it
> there's a different example, this time explicitly calling close() on the
> session:
>
> def run_my_program():
> session = Session()
> try:
> ThingOne().go(session)
> ThingTwo().go(session)
>
> session.commit()
> except:
> session.rollback()
> raise
> finally:
> session.close()
>
>
> So my question is, what does session.close() do that commit/rollback
> does not?

close() will:

1. expunge all objects currently still associated with that Session to
no longer be associated with it

2. safely dispose of any remaining SessionTransaction objects associated
with the Session.

We had a user who required #2 because they built an "after_commit()"
handler that threw errors and would cause the state of the
SessionTransaction to be invalid
(https://bitbucket.org/zzzeek/sqlalchemy/issues/3974/inconsistent-session-state-after-raising).

Therefore, if you're building production code and at the end of your
transaction block, you absolutely want everything to start fresh
regardless of how badly things blew up the last time, call session.close().




>
> It's also not entirely clear to me if a session object can be reused
> after it has been closed.
> At http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.close it says:
>
> "If this session were created with autocommit=False, a new transaction
> is immediately begun. Note that this new transaction does not use any
> connection resources until they are first needed."
>
> So it sounds to me like a closed session *can* be re-used. Is that correct?
>
> Related to this is calling scoped_session.remove.
> At http://docs.sqlalchemy.org/en/latest/orm/contextual.html#unitofwork-contextual it says:
>
> web request ends -> # the registry is instructed to
> # remove the Session
> Session.remove()
>
>
> As I understand it, this calls "close" on the underlying session *and*
> removes it from the registry, so you get a fresh Session next time.
> However if the framework already does a commit/rollback, why not just
> allow the registry to retain the same session object?
>
> Thanks,
>
> Brian.
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google
> Groups "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to sqlalchemy+...@googlegroups.com
> <mailto:sqlalchemy+...@googlegroups.com>.
> To post to this group, send email to sqlal...@googlegroups.com
> <mailto:sqlal...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages