Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sqlalchemy: Using decorator to provide thread-safe session for multiple functions

I am working on something similar like here (multithreaded app with sqlalchemy), so I understood, that I should create a new session for each db-query.

I wonder, if using a decorator for each method, which needs DB-access would make sense, or if there are traps using this approach. The decorator is constructed following the last example here.

def dbconnect(func):
    def inner(*args, **kwargs):
        session = Session()  # with all the requirements
        try:
            func(*args, session=session, **kwargs)
            session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()
    return inner

@dbconnect
def some_function(some, arguments, session)
    session.query(...) # no commit, close, rollback required

some_function("many", "different_arguments") 
#session is not required, since provided by decorator

This would make it comparable easy to provide thread-safe DB-access to any function, without the need of implementing the whole try-except-finally-stuff redundant, but I am not sure, if this approach is fail-safe and pythonic, or if there exists another best-practice.

like image 619
Sebastian Werk Avatar asked Aug 06 '14 09:08

Sebastian Werk


People also ask

Is SQLAlchemy Session thread safe?

Every pool implementation in SQLAlchemy is thread safe, including the default QueuePool . This means that 2 threads requesting a connection simultaneously will checkout 2 different connections. By extension, an engine will also be thread-safe.

What is Sessionmaker in SQLAlchemy?

Session in SQLAlchemy ORM However, to standardize how sessions are configured and acquired, the sessionmaker class is normally used to create a top-level Session configuration which can then be used throughout an application without the need to repeat the configurational arguments.

What is _sa_instance_state in SQLAlchemy?

_sa_instance_state is a non-database-persisted value used by SQLAlchemy internally (it refers to the InstanceState for the instance.

What is Create_engine in SQLAlchemy?

The create_engine() method of sqlalchemy library takes in the connection URL and returns a sqlalchemy engine that references both a Dialect and a Pool, which together interpret the DBAPI's module functions as well as the behavior of the database.


1 Answers

I think it here would make sense to use a scoped_session, maybe like this:

session_factory = sessionmaker(bind=some_engine)
Session = scoped_session(session_factory)

def dbconnect(func):
    def inner(*args, **kwargs):
        session = Session()  # (this is now a scoped session)
        try:
            func(*args, **kwargs) # No need to pass session explicitly
            session.commit()
        except:
            session.rollback()
            raise
        finally:
            Session.remove()  # NOTE: *remove* rather than *close* here
    return inner

@dbconnect
def some_function(some, arguments):
    session = Session()
    # 'session' is  now a handle to the *same* session as in the decorator
    session.query(...) # no commit, close, rollback required

some_function("many", "different_arguments") 
#session is not required, since provided by decorator

(Warning: Untested)

like image 198
ukrutt Avatar answered Sep 19 '22 12:09

ukrutt