【Python】SQLAlchemy:session何时commit,何时close?

SQLAlchemy:session何时commit,何时close?

参考阅读:SQLAlchemy - 官方文档

官方文档说明了关于什么是session,以及如何创建session、如何使用session、如何关闭session

参考阅读 - When do I construct a Session, when do I commit it, and when do I close it?

  1. As a general rule, keep the lifecycle of the session separate and external from functions and objects that access and/or manipulate database data. This will greatly help with achieving a predictable and consistent transactional scope.
    一般来说,将会话的生命周期与访问和/或操作数据库数据的函数和对象分开。这将极大地帮助实现可预测和一致的事务范围。

  2. Make sure you have a clear notion of where transactions begin and end, and keep transactions short, meaning, they end at the series of a sequence of operations, instead of being held open indefinitely.
    确保您对事务在何处开始和结束有一个清晰的概念,并保持事务简短,即它们在一系列操作中结束,而不是无限期地保持打开状态

官方示例

E.g. don’t do this:

### this is the **wrong way to do it** ###

class ThingOne(object):
    def go(self):
        session = Session()
        try:
            session.query(FooBar).update({"x": 5})
            session.commit()
        except:
            session.rollback()
            raise

class ThingTwo(object):
    def go(self):
        session = Session()
        try:
            session.query(Widget).update({"q": 18})
            session.commit()
        except:
            session.rollback()
            raise

def run_my_program():
    ThingOne().go()
    ThingTwo().go()

Keep the lifecycle of the session (and usually the transaction) separate and external:

### this is a **better** (but not the only) way to do it ###

class ThingOne(object):
    def go(self, session):
        session.query(FooBar).update({"x": 5})

class ThingTwo(object):
    def go(self, session):
        session.query(Widget).update({"q": 18})

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

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

The most comprehensive approach, recommended for more substantial applications, will try to keep the details of session, transaction and exception management as far as possible from the details of the program doing its work. For example, we can further separate concerns using a context manager:

### another way (but again *not the only way*) to do it ###

from contextlib import contextmanager

@contextmanager
def session_scope():
    """Provide a transactional scope around a series of operations."""
    session = Session()
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()


def run_my_program():
    with session_scope() as session:
        ThingOne().go(session)
        ThingTwo().go(session)

StackOverflow 上关于如何关闭 SQLAlchemy session 的讨论:

回答1:StackOverflow - How to close a SQLAlchemy session?

如何正确的关闭 SQLAlchemy session?
StackOverflow 上面关于此问题的回答:
在这里插入图片描述

回答2:StackOverflow - How to close a SQLAlchemy session?

如何正确的关闭 SQLAlchemy session?
再看一个 StackOverflow 上面关于此问题的回答:
在这里插入图片描述在这里插入图片描述

回答说:That is, the Engine is a factory for connections as well as a pool of connections, not the connection itself. When you say conn.close(), the connection is returned to the connection pool within the Engine, not actually closed.

也就是说,Engine 相当于一个创建连接的工厂,而不是连接本身。当使用conn.close()时,连接被放回到Engine的连接池当中,而不是真正的关闭了。

如果想要在调用conn.close()时,真正的关闭连接,可以使用poolclass=NullPool属性:

from sqlalchemy.pool import NullPool
db = create_engine('mysql://root@localhost/test_database', poolclass=NullPool)

拓展阅读:MySQL server has gone away 原因分析及解决方式

conn.close() 是把连接放回连接池,不是真正的关闭;池子里的空闲连接在MySQL线程里sleep,长时间不操作,MySQL把连接一端关闭了,所以第二天SQLAlchemy再用这个连接的时候,抛出MySQL server has gone away…

发布了552 篇原创文章 · 获赞 201 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/sinat_42483341/article/details/103776875