flask-security + SQLAlchemy:在无效事务回滚之前无法重新连接

问题描述

编辑:

环境:

Python 3.8.3

Flask==1.1.2
Flask-Login==0.5.0
Flask-Security==3.0.0
sqlAlchemy==1.3.19

数据库MysqL 5.6.45,InnoDB表。

我是flask-securitysqlAlchemy的新手。我参考了flask-security的文档,然后尝试以下方法

engine = create_engine(
    db_source,encoding="utf-8",pool_size=64,pool_timeout=300,pool_recycle=3,max_overflow=64
)
db_session = scoped_session(
    sessionmaker(
        autocommit=False,autoflush=False,bind=engine
    )
)
Base = declarative_base()
Base.query = db_session.query_property()

# some codes define the classes Role and User for flask-security

user_datastore = sqlAlchemySessionUserDatastore(
    db_session,User,Role
)
security = Security(app,user_datastore)

   .
   .
   .

@app.route("/test/",methods=["GET","POST"])
@login_required
def api_test():
    # do something

在开始时,flask-security内置登录页面登录过程开始运行。但是,一段时间后,登录过程将获得“内部服务器错误”,并且日志显示sqlalchemy.exc.StatementError:(sqlalchemy.exc.InvalidRequestError)在无效事务回滚之前无法重新连接”。

搜索了一些类似的问题,他们说我需要做这样的事情以进行回滚:

try:
    # this is where the "work" happens!
    yield session
    # always commit changes!
    session.commit()
except:
    # if any kind of exception occurs,rollback transaction
    session.rollback()
    raise
finally:
    session.close()

但是,我所有的代码都不会在任何地方调用session.commit(),所以我不确定session.rollback()的放置位置。

我的问题是:

  1. 如果session.rollback()有帮助,即使我没有在代码调用session.commit(),该如何放置?
  2. 我猜这是烧瓶安全性内在的东西吗?如果是,该如何解决
  3. 问题可能出在我错误地使用了scoped_session吗? scoped_session不会回滚/删除自身吗?

编辑:

感谢@jwag,我将尽力更准确地描述问题。

  1. 首先,我在服务器上启动该应用程序。目前,登录过程运行良好。
  2. 但是,过一段时间(这意味着“此”应用程序至少在一天之内再也不会连接到数据库,但实际上我不确定问题何时开始出现)。发生“直到无效的事务被回滚之前才重新连接”的问题。
  3. 还有另一个应用程序通过MysqL.connector连接到其他表的同一数据库。即使我的应用程序遇到“在无效交易回滚之前也无法重新连接”的问题,该应用程序始终运行良好。该问题一直持续到我重新启动httpd服务。

我的问题似乎与此问题非常相似:

SQLAlchemy: Can't reconnect until invalid transaction is rolled back

唯一的区别是我不仅使用sqlAlchemy,而且还使用flask-security,所以我什至不知道在哪里回滚/关闭会话-甚至问题不同,但我不知道。

我认为问题不在于用户/角色模型(错误消息并不指向这些模型),但是无论如何我在下面显示了它们。

class RolesUsers(Base):
    __tablename__ = "roles_users"
    __table_args__ = {
        "MysqL_engine": "InnoDB","MysqL_charset": "utf8mb4"
    }
    id = Column(Integer(),primary_key=True)
    user_id = Column("user_id",Integer(),ForeignKey("user.id"))
    role_id = Column("role_id",ForeignKey("role.id"))

class Role(Base,RoleMixin):
    __tablename__ = "role"
    __table_args__ = {
        "MysqL_engine": "InnoDB",primary_key=True)
    name = Column(String(20),unique=True)
    description = Column(String(128))

class User(Base,UserMixin):
    __tablename__ = "user"
    __table_args__ = {
        "MysqL_engine": "InnoDB","MysqL_charset": "utf8mb4"
    }
    id = Column(Integer,primary_key=True)
    email = Column(String(128),unique=True)
    username = Column(String(128))
    password = Column(String(128))
    last_login_at = Column(DateTime())
    current_login_at = Column(DateTime())
    last_login_ip = Column(String(100))
    current_login_ip = Column(String(100))
    login_count = Column(Integer)
    active = Column(Boolean())
    roles = relationship(
        "Role",secondary="roles_users",backref=backref("users",lazy="dynamic")
    )

解决方法

您没有说您使用的是什么版本的Flask-Security。一般而言-实际的解决方案是弄清楚为什么会收到“无效语句错误”并进行修复。不尝试回滚。根据您的后端数据库(您是否使用pycopg2?),我发现如果尝试使用不正确的类型进行SELECT(例如,该列是一个int且您传递了一个字符串),它将引发这种错误。

在代码段中,您定义了“ db_session”,但您将查询定义为“ backstage_db_session”?

最后-当您说“一段时间后”并且“您不提交”时-是否意味着您的应用程序永远不会读取或写入数据库?

最后,如果需要更多帮助,请提供用户模型代码。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...