Flask/Apache 中的 PyMySQL 有时会返回空结果
PyMySQL in Flask/Apache sometimes returning empty result
我有一个 Flask 应用程序,在 Apache 中是 运行,它依赖于 PyMySQL。该应用程序提供了一系列 REST 命令。 运行ning 下 Python 3.
在不提供完整源代码的情况下,程序结构如下:
#!flask/bin/python
import json
import pymysql
from flask import *
# Used to hopefully share the connection if the process isn't restarted
mysql_connection = None
# Gets the mysql_connection, or opens it
GetStoreCnx():
global mysql_connection
if (mysql_connection != None):
store_connection_string = ""
# Get the connection string from the config file
with open('config/storedb.json', 'r') as f:
store_connection_string = json.load(f)
mysql_connection = pymysql.connect(**store_connection_string)
return mysql_connection;
class Server(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Return results via REST
@app.route('/results1', methods=['GET'])
def get_result1():
cnx = GetStoreCnx();
cursor = cnx.cursor();
query = """
SELECT
result_name,
successful
FROM
results
"""
cursor.execute(query)
cnx.commit()
result = cursor.fetchall()
return json.dumps(result)
# Run server, if needed
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
还有一些 REST 调用 - 但它们本质上都做同样的事情(即 - 获取连接、创建游标、运行 基本 select 查询 - 有时确实有超过 2 个字段,执行查询,获取结果并将其 return 作为 JSON 对象)。那里的提交应该是不必要的,但这似乎是 PyMySQL 的一个 运行ning 问题,导致获取旧数据。
问题是这些 REST 调用有时 return 空 JSON 集(即 []
),进一步调查表明执行调用有时 return 完全空结果但不抛出异常。这种情况经常发生——但并非总是如此。一些调用成功地执行 return 值。当我尝试保持通话直到结果 return 时(如:
while(cursor.execute(query) < 1):
pass
) 该进程进入无限循环,最终(迅速)阻止 apache 为任何更多请求提供服务。
服务器(目前)每秒仅服务大约 5 个调用。如果我使用开发服务器,则不会出现此问题。
有什么办法可以防止这个错误吗?是 PyMySQL 的错误吗?我正在做的事情阻止了与 MySQL 的正确连接吗?
您正在创建一个供您的应用程序使用的全局 mysql 连接,但是 pymysql 声明一个 threadsafety
of 1, which according to the dbapi2 specification 意味着:
1 Threads may share the module, but not connections.
由于 flask 中的并发请求将由不同的线程处理,因此您不应共享连接。使用开发服务器时没有遇到任何问题的原因是它运行单线程。
要避免这种情况,您可以:
- 为每个线程创建一个新连接,将其存储为线程本地以供进一步使用
- 为每个请求创建一个新连接,将其存储在
flask.g
中以供进一步使用
为此,您的 GetStoreCnx
函数可以这样更改:
import threading
thread_local = threading.local()
def GetStoreCnx():
if not hasattr(thread_local, 'mysql_connection'):
store_connection_string = ""
# Get the connection string from the config file
with open('config/storedb.json', 'r') as f:
store_connection_string = json.load(f)
mysql_connection = pymysql.connect(**store_connection_string)
thread_local.mysql_connection = mysql_connection
return thread_local.mysql_connection;
SQLAlchemy 的 scoped_session()
做了类似的事情。对于每个请求一个连接,这也应该与 flask.g
而不是 thread_local
一起使用。
我有一个 Flask 应用程序,在 Apache 中是 运行,它依赖于 PyMySQL。该应用程序提供了一系列 REST 命令。 运行ning 下 Python 3.
在不提供完整源代码的情况下,程序结构如下:
#!flask/bin/python
import json
import pymysql
from flask import *
# Used to hopefully share the connection if the process isn't restarted
mysql_connection = None
# Gets the mysql_connection, or opens it
GetStoreCnx():
global mysql_connection
if (mysql_connection != None):
store_connection_string = ""
# Get the connection string from the config file
with open('config/storedb.json', 'r') as f:
store_connection_string = json.load(f)
mysql_connection = pymysql.connect(**store_connection_string)
return mysql_connection;
class Server(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Return results via REST
@app.route('/results1', methods=['GET'])
def get_result1():
cnx = GetStoreCnx();
cursor = cnx.cursor();
query = """
SELECT
result_name,
successful
FROM
results
"""
cursor.execute(query)
cnx.commit()
result = cursor.fetchall()
return json.dumps(result)
# Run server, if needed
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
还有一些 REST 调用 - 但它们本质上都做同样的事情(即 - 获取连接、创建游标、运行 基本 select 查询 - 有时确实有超过 2 个字段,执行查询,获取结果并将其 return 作为 JSON 对象)。那里的提交应该是不必要的,但这似乎是 PyMySQL 的一个 运行ning 问题,导致获取旧数据。
问题是这些 REST 调用有时 return 空 JSON 集(即 []
),进一步调查表明执行调用有时 return 完全空结果但不抛出异常。这种情况经常发生——但并非总是如此。一些调用成功地执行 return 值。当我尝试保持通话直到结果 return 时(如:
while(cursor.execute(query) < 1):
pass
) 该进程进入无限循环,最终(迅速)阻止 apache 为任何更多请求提供服务。
服务器(目前)每秒仅服务大约 5 个调用。如果我使用开发服务器,则不会出现此问题。
有什么办法可以防止这个错误吗?是 PyMySQL 的错误吗?我正在做的事情阻止了与 MySQL 的正确连接吗?
您正在创建一个供您的应用程序使用的全局 mysql 连接,但是 pymysql 声明一个 threadsafety
of 1, which according to the dbapi2 specification 意味着:
1 Threads may share the module, but not connections.
由于 flask 中的并发请求将由不同的线程处理,因此您不应共享连接。使用开发服务器时没有遇到任何问题的原因是它运行单线程。
要避免这种情况,您可以:
- 为每个线程创建一个新连接,将其存储为线程本地以供进一步使用
- 为每个请求创建一个新连接,将其存储在
flask.g
中以供进一步使用
为此,您的 GetStoreCnx
函数可以这样更改:
import threading
thread_local = threading.local()
def GetStoreCnx():
if not hasattr(thread_local, 'mysql_connection'):
store_connection_string = ""
# Get the connection string from the config file
with open('config/storedb.json', 'r') as f:
store_connection_string = json.load(f)
mysql_connection = pymysql.connect(**store_connection_string)
thread_local.mysql_connection = mysql_connection
return thread_local.mysql_connection;
SQLAlchemy 的 scoped_session()
做了类似的事情。对于每个请求一个连接,这也应该与 flask.g
而不是 thread_local
一起使用。