SQLAlchemy session 使用问题

SQLAlchemy session 使用问题
在更改 SQLAlchemy Session 从每次请求都创建到共享同一个 Session 之后遇到了如下问题:
StatementError: (sqlalchemy.exc.InvalidRequestError) Can’t reconnect until invalid transaction is rolled back [SQL: ]
或者是
raised unexpected: OperationalError(“(_mysql_exceptions.OperationalError) (2006, ‘ MySQL server has gone away’)”,)
错误是 SQLAlchemy 抛出。原因是你从 pool 拿的 connection 没有以 session.commit 或 session.rollback 或者 session.close 放回 pool 里。这时 connection 的 transaction 没有完结(rollback or commit)。 而不知什么原因(recyle 了,timeout 了)你的 connection 又死掉了,你的 sqlalchemy 尝试重新连接。由于 transaction 还没完结,无法重连。
正确用法是确保 session 在使用完成后用 session.close, session.commit 或者 session.rollback 把连接还回 pool。
SQLAlchemy 数据库连接池使用
sessions 和 connections 不是相同的东西, session 使用连接来操作 数据库 ,一旦任务完成 session 会将数据库 connection 交还给 pool。
在使用
create_engine
创建引擎时,如果默认不指定连接池设置的话,一般情况下,SQLAlchemy 会使用一个 QueuePool 绑定在新创建的引擎上。并附上合适的连接池参数。
在以默认的方法 create_engine 时(如下),就会创建一个带连接池的引擎。
engine = create_engine('mysql+mysqldb://root:password@127.0.0.1:3306/dbname')
在这种情况下,当你使用了 session 后就算显式地调用 session.close(),也不能把连接关闭。连接会由 QueuePool 连接池进行管理并复用。
这种特性在一般情况下并不会有问题,不过当数据库 服务器 因为一些原因进行了重启的话。最初保持的数据库连接就失效了。随后进行的 session.query() 等方法就会抛出异常导致程序出错。
如果想禁用 SQLAlchemy 提供的数据库连接池,只需要在调用 create_engine 是指定连接池为 NullPool,SQLAlchemy 就会在执行 session.close() 后立刻断开数据库连接。当然,如果 session 对象被析构但是没有被调用 session.close(),则数据库连接不会被断开,直到程序终止。
下面的代码就可以避免 SQLAlchemy 使用连接池:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPool
engine = create_engine('mysql+mysqldb://root:password@127.0.0.1:3306/dbname', poolclass=NullPool)
Session = sessionmaker(bind=engine)
session = Session()
usr_obj_list = session.query(UsrObj).all()