【问题标题】:flask-security + SQLAlchemy: can't reconnect until invalid transaction is rolled backflask-security + SQLAlchemy:在回滚无效事务之前无法重新连接
【发布时间】:2021-02-06 03:33:00
【问题描述】:

编辑:

环境:

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-security 和 SQLAlchemy 的新手。我参考了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_sessionscoped_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", Integer(), ForeignKey("role.id"))

class Role(Base, RoleMixin):
    __tablename__ = "role"
    __table_args__ = {
        "mysql_engine": "InnoDB",
        "mysql_charset": "utf8mb4"
    }
    id = Column(Integer(), 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")
    )

【问题讨论】:

    标签: python sqlalchemy flask-security


    【解决方案1】:

    您没有说您使用的是哪个版本的 Flask-Security。一般来说 - 解决这个问题的实际解决方案是找出为什么你会收到 Invalid Statement Error 并修复它。不尝试回滚。根据您的后端数据库(您使用的是 pycopg2 吗?)我发现如果您尝试使用不正确的类型进行 SELECT(例如,该列是一个 int 并且您传递一个字符串) - 它会抛出这种错误。

    在您的代码 sn-p 中,您定义了“db_session”,但您将查询定义为“backstage_db_session”??

    最后——当你说“一段时间后”和“你不提交”——这是否意味着你的应用永远不会读取或写入数据库?

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

    【讨论】:

      猜你喜欢
      • 2015-09-16
      • 2020-02-11
      • 2017-04-26
      • 2014-11-29
      • 2021-03-06
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 2017-02-14
      相关资源
      最近更新 更多