mysql Flask-SQLAlchemy:在回滚无效事务之前无法重新连接

ohtdti5x  于 2023-08-02  发布在  Mysql
关注(0)|答案(7)|浏览(149)

因此,我使用Amazon Web Services RDS来运行MySQL服务器,使用Python的Flask框架来运行应用服务器,并使用Flask-SQLAlchemy与RDS接口。
我的应用config.py

SQLALCHEMY_DATABASE_URI = '<RDS Host>'
SQLALCHEMY_POOL_RECYCLE = 60

字符串
My __ init __.py

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

application = Flask(__name__)
application.config.from_object('config')
db = SQLAlchemy(application)


我有我的主application.py

from flask import Flask
from application import db
import flask.ext.restless
from application.models import Person

application = Flask(__name__)
application.debug=True
db.init_app(application)

@application.route('/')
def index():
    return "Hello, World!"

manager = flask.ext.restless.APIManager(application, flask_sqlalchemy_db=db)
manager.create_api(Person, methods=['GET','POST', 'DELETE'])

if __name__ == '__main__':
    application.run(host='0.0.0.0')


models.py

class Person(db.Model):
    __bind_key__= 'people'
    id = db.Column(db.Integer, primary_key=True)
    firstName = db.Column(db.String(80))
    lastName = db.Column(db.String(80))
    email = db.Column(db.String(80))

    def __init__(self, firstName=None, lastName=None, email=None):
        self.firstName = firstName
        self.lastName = lastName
        self.email = email


然后,我有一个脚本来填充数据库,以便在创建数据库和启动应用程序后进行测试:

from application import db
from application.models import Person

person = Person('Bob', 'Jones', 'bob@website.net')
db.session.add(person)
db.session.commit()


一旦我用db.drop_all()和db.create_all()重置了数据库,我就启动application.py,然后启动脚本来填充数据库。
服务器会用正确的JSON响应,但如果我几个小时后回来检查,我会得到一个错误,我需要回滚,或者有时是2006年的错误,MySQL服务器已经消失了。
人们建议我更改MySQL服务器上的超时设置,但这并没有解决任何问题。以下是我的设置:

innodb_lock_wait_timeout = 3000
max_allowed_packet       = 65536
net_write_timeout        = 300
wait_timeout             = 300


然后,当我查看RDS监视器时,它显示MySQL服务器保持连接打开了相当长的一段时间,直到超时。如果我错了请纠正我,但连接不是应该在完成后关闭吗?似乎应用服务器一直确保数据库连接存在,然后当MySQL服务器超时时,Flask/Flask-SQLAlchemy抛出一个错误,并导致应用服务器关闭。
任何建议都很感谢,谢谢!

4bbkushb

4bbkushb1#

我想是因为

db.init_app(application)

字符串
在application.py上,从那以后就没有出现过错误。

nkhmeac6

nkhmeac62#

每次检查是否回滚都很麻烦。
我做了需要提交的插入,更新函数。

@app.teardown_request
def session_clear(exception=None):
    Session.remove()
    if exception and Session.is_active:
        Session.rollback()

字符串

osh3o9ms

osh3o9ms3#

这似乎不是事务的问题,但这可能是由MySQL错误(如Connection reset by peer)引起的。这意味着您的连接丢失,可能是因为您的应用程序上下文设置不正确。
一般来说,最好使用工厂模式来创建应用程序。这有很多优点,你的代码是

  • 易于阅读和设置
  • 更容易测试
  • 避免循环进口

为了防止无效事务错误(可能由OperationalError: Connection reset by peer引起),您应该确保正确处理数据库连接。
下面的示例基于this article,它很好地解释了flask应用程序上下文,以及如何将其与数据库连接或任何其他扩展一起使用。
application.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

def create_app():
    """Construct the core application."""
    application = Flask(__name__)
    application.config.from_object('config')    # Set globals
    db = SQLAlchemy()

    with application.app_context():
        # Initialize globals/extensions in app context
        db.init_app(app)        

        # import routes here
        from . import routes

    return application

if __name__ == "__main__":
   app = create_app()
   app.run(host="0.0.0.0")

字符串
routes.py

from flask import current_app as application

@application.route('/', methods=['GET'])
def index():
   return "Hello, World!"


如果您仍然遇到断开连接问题,您还应该查看SQLAlchemy文档中有关处理断开连接的内容,并查看this question

q1qsirdb

q1qsirdb4#

这里你错过了池回收,因为MySql在一段时间后关闭会话,所以你需要添加池回收,以便池中的连接在池回收时间后重新连接。
第一个月

gijlo24d

gijlo24d5#

这个错误通常出现在你创建sqlalchemy引擎作为一个单例的时候。在这种情况下,在连接无效后(在我的情况下是3600秒),您会收到InvalidTransaction错误。
最好的建议是在应用程序初始化时初始化db会话

db.init_app(app)

字符串
并在需要执行CRUD操作时导入此数据库会话。
从来没有遇到过这个问题后,我的应用程序的这一变化。

ddarikpa

ddarikpa6#

如果你在代码中使用“db”作为导入对象。你必须始终确保db在当前的flask上下文中。

让我们举个例子:

flask 应用程序:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')

with app.app_context():
    db = SQLAlchemy(app)
    from app.Model import Models
    db.create_all()
    from app import Rountes

字符串

如何在任何地方和任何线程中使用具有当前应用上下文的数据库?

1:每次要访问数据库时,将其与app.app_context()一起使用:

from app import app

 def test_query():
     with app.app_context():
         db.session.commit()
         clients = Client.query.all()
         #etc...


2:使用装饰器使其更容易,更易读:

from app import app

def flask_ctx(func):
    def decorated_view(*args, **kwargs):
        from app import app
        with app.app_context():
            return func(*args, **kwargs)
    return decorated_view

@flask_ctx
def test_query():
    db.session.commit()
    clients = Client.query.all()
    #etc...

pprl5pva

pprl5pva7#

或者,在填充数据库的脚本的末尾使用以下命令:

db.session.close()

字符串
这应该可以防止那些恼人的“MySQL服务器已经消失”错误。

相关问题