Python 从多个uWSGI工作者查询MySQL返回不匹配的行

Python 从多个uWSGI工作者查询MySQL返回不匹配的行,python,mysql,flask,uwsgi,pymysql,Python,Mysql,Flask,Uwsgi,Pymysql,我正在运行一个针对MySQL数据库的查询,该数据库来自一个Flask应用程序,该应用程序使用uWSGI和多个worker运行。我注意到,有时当我按id查询资源时,返回行的id与我查询时使用的id不同 我认为查询隔离意味着这是不可能的。然而,MySQL似乎把查询搞混了。在不使用uWSGI时,我无法再现这一点,但这可能只是因为它在本地主机上运行,而不是在单独测试Flask服务器时在服务器上运行 为什么输入id和结果id不匹配 from flask import Flask import pymysq

我正在运行一个针对MySQL数据库的查询,该数据库来自一个Flask应用程序,该应用程序使用uWSGI和多个worker运行。我注意到,有时当我按id查询资源时,返回行的id与我查询时使用的id不同

我认为查询隔离意味着这是不可能的。然而,MySQL似乎把查询搞混了。在不使用uWSGI时,我无法再现这一点,但这可能只是因为它在本地主机上运行,而不是在单独测试Flask服务器时在服务器上运行

为什么输入id和结果id不匹配

from flask import Flask
import pymysql.cursor, random

class Database:
    def __init__(self, user, password, host, database):
        self.connection = pymysql.connect(
            user=user,
            password=password,
            host=host,
            database=database,
            cursorclass=pymysql.cursors.DictCursor
        )

    def query(self, sql, **kwargs):
        with self.connection.cursor() as cursor:
            cursor.execute(sql, kwargs)
            return cursor

app = Flask(__name__)
database = Database('user', 'password', 'localhost', 'database')

@app.route('/resources/<path:id>')
def resource(id):
    item = database.query(
        'SELECT resources.id FROM resources WHERE resources.id = %(id)s',
        id=id
    ).fetchone()

    identifier = random.random()
    print(identifier, 'ID 1:', id)
    print(identifier, 'ID 2:', item['id'])

    if int(item['id']) != int(id):
        print('Error found!!!')

    return 'Done', 200

if __name__ == '__main__':
    app.run()

对于其他面临此问题的人,我找到了以下解决方案。

根据

只要可能,uWSGI尝试(ab)使用fork()调用的写时复制语义。默认情况下,它将在加载应用程序后分叉,以尽可能多地共享它们的内存。如果出于某种原因不希望出现这种行为,请使用lazy apps选项。这将指示uWSGI在每个工人的fork()之后加载应用程序

看了一眼之后,我意识到我的问题与创建多个流程有关

但是,由于默认情况下uWSGI从一个主辅助进程加载所有进程(并且每次都不运行整个Flask应用程序),因此所有辅助进程最终都共享一个数据库连接(结果不太好!)


解决方案是包含
lazy apps
参数,该参数强制在创建每个worker时运行所有代码。

我对uwsgi也有同样的问题,在运行一天后,一些记录丢失,即使它们存在于数据库中。但我不明白共享数据库连接是如何导致这个问题的??!它们不仅仅共享同一个连接,它们实际上在内存中共享同一个Python
数据库
对象!在我的示例中(参见问题),这导致了同时运行不同查询的两个fork之间的竞争条件。这意味着不同调用方的查询结果有时会由我的共享
数据库
对象返回。