Personally I wouldn't use decorators for this. I would make every function that needs to interact with the database take an explicit session parameter, and I would use the facilities of the web framework to create the session at the beginning of the request and close it at the end. I've never used Flask, but I see it has a "signals" mechanism (http://flask.pocoo.org/docs/0.12/api/#signals) with request_started and request_finished events. You could use the request_started signal to create the session and attach it to the request object, and clean it up in request_finished.
Looking at the Flask docs, I think you could also write a simple extension. They have a SQLite example at http://flask.pocoo.org/docs/0.12/extensiondev/#the-extension-code, which you ought to be able to adapt for SQLAlchemy. The app context is per-request, so it should be safe (http://flask.pocoo.org/docs/0.12/appcontext/#locality-of-the-context). Hope that helps, Simon On Thu, Feb 15, 2018 at 9:52 AM, <eugene.de...@gmail.com> wrote: > Hello, Simon! > So what better way? > Something like this? > SESSION = sessionmaker(bind=engine, autocommit=True) > > > > @decorator_with_args > def session_decorator(func, default=None): > def wrapper(*a, **kw): > session = SESSION() > session.begin(subtransactions=True) > if 'session' not in kw: > kw['session'] = session > try: > return func(*a, **kw) > except Exception as e: > session.rollback() > logging.error(e) > return default > finally: > if session.is_active: > session.commit() > session.close() > return wrapper > > I try create additional function > > @session_decorator() > def execute(statement, **kwargs): > session = kwargs['session'] > fetch = kwargs.get('fetch', 'all') > result = session.execute(statement) > if fetch == 'all': > return result.fetchall() > elif fetch is False: > return True > elif fetch == 'count': > return result > return result.fetchone() > > and use it in all execute statements, but that not help. > Still receive error > This result object does not return rows. It has been closed automatically. > But how it closed if that another session? > Can you correct my code? > > > > > среда, 14 февраля 2018 г., 17:45:59 UTC+3 пользователь Simon King написал: >> >> I think there are a couple of problems with this. >> >> 1. You are calling scoped_session and sessionmaker every time the >> decorated function is called, which is unnecessary. sessionmaker >> returns a factory function for creating sessions, so you typically >> only have one sessionmaker() call in your application. You could >> either make it a module-global, or do it during application >> configuration. >> >> 2. You are never calling session.close(). This means that the >> transaction started by a web request will stay open after the request >> ends. Since you are using scoped_session as well, the session is >> maintained as a thread-local object, so when the thread handles >> another web request, it will use the same session and the same >> transaction. Your long-running transactions are probably the reason >> why you are getting blocked requests. >> >> You might like to read >> >> http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#session-frequently-asked-questions. >> >> I was going to say that you need to add a "finally" section to your >> session_decorator that calls session.close(), but if you ever have one >> decorated function calling another decorated function, they are going >> to interfere with each other. If you are *absolutely certain* that >> will never happen, adding the "finally" section will probably improve >> things, but I would recommend that you try to structure your app a >> little differently, so that the session creation and teardown happen >> at the beginning and end of the web request. >> >> Hope that helps, >> >> Simon >> >> >> On Wed, Feb 14, 2018 at 2:14 PM, <eugene...@gmail.com> wrote: >> > Decorator like this >> > >> > engine = create_engine( >> > >> > >> > 'mssql+pymssql://{LOGIN}:{PASSWORD}@{HOST}/{DATABASE}?charset={CHARSET}&timeout={TIMEOUT}'.format(**DATABASE), >> > isolation_level='READ COMMITTED' >> > ) >> > >> > >> > def decorator_with_args(decorator_to_enhance): >> > """ >> > https://habrahabr.ru/post/141501/ >> > """ >> > def decorator_maker(*args, **kwargs): >> > def decorator_wrapper(func): >> > return decorator_to_enhance(func, *args, **kwargs) >> > return decorator_wrapper >> > return decorator_maker >> > >> > >> > def scope_func(): >> > return scoped_session(sessionmaker(bind=engine, autocommit=True))() >> > >> > >> > @decorator_with_args >> > def session_decorator(func, default=None, **kwargs): >> > def wrapper(*a, **kw): >> > session = scope_func() >> > if 'session' not in kw: >> > kw['session'] = session >> > try: >> > return func(*a, **kw) >> > except Exception as e: >> > session.rollback() >> > >> > print('#####FUNCTION NAME: {}'.format(func.__name__)) >> > >> > print(e) >> > logging.error(e) >> > return default >> > return wrapper >> > >> > >> > >> > >> > среда, 14 февраля 2018 г., 17:06:54 UTC+3 пользователь Simon King >> > написал: >> >> >> >> The pattern you should be aiming for is one in which a fresh >> >> transaction is started for every web request that touches the >> >> database, and that the transaction is closed at the end of the >> >> request. How are you ensuring that at the moment? >> >> >> >> Simon >> >> >> >> On Wed, Feb 14, 2018 at 12:51 PM, <eugene...@gmail.com> wrote: >> >> > If I run tests where all functions run one-by-one - all tests passed. >> >> > But when i run web app and functions can call almost in parallel then >> >> > i >> >> > have >> >> > a problem, then there are problems - transactions can block each >> >> > other. >> >> > I tried to set the isolation level of SNAPSHOT and READ COMMITTED, >> >> > but >> >> > it >> >> > did not help. >> >> > >> >> > среда, 14 февраля 2018 г., 14:58:37 UTC+3 пользователь >> >> > eugene...@gmail.com >> >> > написал: >> >> >> >> >> >> Hello, Mike! >> >> >> In my web app i have many selects like >> >> >> session.execute(select([table1]).where(condition)) >> >> >> and not so much updates, inserts and deletes like >> >> >> session.execute(update(table1).where(condition).values(**values)) >> >> >> session.execute(insert(table1).values(**values)) >> >> >> session.execute(delete(table1).where(condition)) >> >> >> >> >> >> What better way to create session for web application? >> >> >> Without additional components like flask-sqlalchemy. >> >> >> >> >> >> суббота, 27 января 2018 г., 20:23:05 UTC+3 пользователь Mike Bayer >> >> >> написал: >> >> >>> >> >> >>> On Sat, Jan 27, 2018 at 5:49 AM, Евгений Рымарев >> >> >>> <rymarev...@gmail.com> wrote: >> >> >>> > I receive this error: >> >> >>> > This result object does not return rows. It has been closed >> >> >>> > automatically. >> >> >>> >> >> >>> there's a lot of weird situations which can cause that error, >> >> >>> usually >> >> >>> when using a connection that has had some failure condition occur >> >> >>> upon >> >> >>> it which renders the connection unusable until either a transaction >> >> >>> is >> >> >>> rolled back or sometimes the connection needs to be discarded. >> >> >>> We >> >> >>> can't diagnose it without a full example that reproduces it as well >> >> >>> as >> >> >>> the complete stack trace. >> >> >>> >> >> >>> >> >> >>> > >> >> >>> > >> >> >>> > >> >> >>> > суббота, 27 января 2018 г., 1:09:53 UTC+3 пользователь Mike Bayer >> >> >>> > написал: >> >> >>> >> >> >> >>> >> On Fri, Jan 26, 2018 at 4:21 PM, Евгений Рымарев >> >> >>> >> <rymarev...@gmail.com> wrote: >> >> >>> >> > Hello, everyone! >> >> >>> >> > Engine: >> >> >>> >> > engine = create_engine( >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > 'mssql+pymssql://{LOGIN}:{PASSWORD}@{HOST}/{DATABASE}?charset={CHARSET}'.format(**DATABASE), >> >> >>> >> > isolation_level='READ COMMITTED' >> >> >>> >> > ) >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > My first decorator for session: >> >> >>> >> > @decorator_with_args >> >> >>> >> > def session_decorator(func, default=None): >> >> >>> >> > def wrapper(*a, **kw): >> >> >>> >> > s = Session(engine) >> >> >>> >> > kw['session'] = s >> >> >>> >> > try: >> >> >>> >> > return func(*a, **kw) >> >> >>> >> > except Exception as e: >> >> >>> >> > func(*a, **kw) >> >> >>> >> > s.rollback() >> >> >>> >> > s.close() >> >> >>> >> > logging.error(e) >> >> >>> >> > return default >> >> >>> >> > finally: >> >> >>> >> > s.commit() >> >> >>> >> > s.close() >> >> >>> >> > return wrapper >> >> >>> >> > >> >> >>> >> > My second decorator for session: >> >> >>> >> > session = scoped_session(sessionmaker(bind=engine)) >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > @decorator_with_args >> >> >>> >> > def session_decorator(func, default=None): >> >> >>> >> > def wrapper(*a, **kw): >> >> >>> >> > kw['session'] = session >> >> >>> >> > try: >> >> >>> >> > return func(*a, **kw) >> >> >>> >> > except Exception as e: >> >> >>> >> > session.remove() >> >> >>> >> > logging.error(e) >> >> >>> >> > return default >> >> >>> >> > finally: >> >> >>> >> > session.remove() >> >> >>> >> > return wrapper >> >> >>> >> > >> >> >>> >> > In both attempts, I came to the conclusion that sessions can >> >> >>> >> > block >> >> >>> >> > other >> >> >>> >> > sessions. >> >> >>> >> > How correctly to create a session once, so that it can be used >> >> >>> >> > throughout >> >> >>> >> > the web application and no locks were created? >> >> >>> >> >> >> >>> >> The Session doesn't create locks, transactions and your database >> >> >>> >> does. >> >> >>> >> >> >> >>> >> What is the nature of these "blocks", are they deadlocks between >> >> >>> >> tables or rows? What operations are prevented from proceeding? >> >> >>> >> Are >> >> >>> >> the locks timing out? SQL Server has graphical consoles that >> >> >>> >> can >> >> >>> >> show you this. >> >> >>> >> >> >> >>> >> What version of SQL Server is this? Do you have >> >> >>> >> ALLOW_SNAPSHOT_ISOLATION and READ_COMMITTED_SNAPSHOT turned on? >> >> >>> >> >> >> >>> >> >> >> >>> >> > >> >> >>> >> > -- >> >> >>> >> > 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. >> >> >>> >> > To post to this group, send email to >> >> >>> >> > sqlal...@googlegroups.com. >> >> >>> >> > Visit this group at >> >> >>> >> > https://groups.google.com/group/sqlalchemy. >> >> >>> >> > For more options, visit https://groups.google.com/d/optout. >> >> >>> > >> >> >>> > -- >> >> >>> > 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. >> >> >>> > To post to this group, send email to sqlal...@googlegroups.com. >> >> >>> > Visit this group at https://groups.google.com/group/sqlalchemy. >> >> >>> > For more options, visit https://groups.google.com/d/optout. >> >> > >> >> > -- >> >> > 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. >> >> > To post to this group, send email to sqlal...@googlegroups.com. >> >> > Visit this group at https://groups.google.com/group/sqlalchemy. >> >> > For more options, visit https://groups.google.com/d/optout. >> > >> > -- >> > 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. >> > To post to this group, send email to sqlal...@googlegroups.com. >> > Visit this group at https://groups.google.com/group/sqlalchemy. >> > For more options, visit https://groups.google.com/d/optout. > > -- > 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+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at https://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- 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+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.