SQLAlchemy Tutorial | Lost connection to MySQL server during query

  • 原创
  • Madman
  • /
  • /
  • 0
  • 1749 次阅读

sqlalchemy.png

Synopsis: 应用长时间无请求访问时,最近一次请求数据库将报错 Lost connection to MySQL server during query。这个过程有可能会很久,从而导致 Web 服务端返回响应时长过久(比如分钟级别)

1. 问题描述

MySQL 连接默认 8 小时没有使用时将被服务端关闭:

mysql> show global variables like 'wait_timeout%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

mysql> show session variables like 'wait_timeout%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

如果你的应用超过这个时间都没有请求,再次查询数据库时将报错 Lost connection to MySQL server during query

准备测试环境:

python3 -m venv venv
source venv/bin/activate
pip install sqlalchemy pymysql

准备测试脚本:

import time

from sqlalchemy.engine import create_engine


url = 'mysql+pymysql://root:123456@127.0.0.1:3306/test'
engine = create_engine(url)

query = 'SELECT now();'

while True:
    print('Query-01', engine.execute(query).fetchall())
    engine.execute('SET wait_timeout=3')  # set session variable `wait_timeout`
    time.sleep(5)
    print('Query-02', engine.execute(query).fetchall())

执行脚本:

(venv) [root@aliyun test]# python test.py 
Query-01 [(datetime.datetime(2020, 12, 12, 11, 7, 20),)]
Traceback (most recent call last):
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 127
7, in _execute_context    cursor, statement, parameters, context
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/default.py", line 
593, in do_execute    cursor.execute(statement, parameters)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/cursors.py", line 163, in ex
ecute    result = self._query(query)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/cursors.py", line 321, in _q
uery    conn.query(q)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 505, i
n query    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 724, i
n _read_query_result    result.read()
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 1069, 
in read    first_packet = self.connection._read_packet()
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 646, i
n _read_packet    packet_header = self._read_bytes(4)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 699, i
n _read_bytes    CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    print('Query-02', engine.execute(query).fetchall())
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 223
5, in execute    return connection.execute(statement, *multiparams, **params)
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 100
3, in execute    return self._execute_text(object_, multiparams, params)
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 117
8, in _execute_text    parameters,
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 131
7, in _execute_context    e, statement, parameters, cursor, context
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 151
1, in _handle_dbapi_exception    sqlalchemy_exception, with_traceback=exc_info[2], from_=e
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/util/compat.py", line 182
, in raise_    raise exception
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 127
7, in _execute_context    cursor, statement, parameters, context
  File "/root/test/venv/lib64/python3.6/site-packages/sqlalchemy/engine/default.py", line 
593, in do_execute    cursor.execute(statement, parameters)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/cursors.py", line 163, in ex
ecute    result = self._query(query)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/cursors.py", line 321, in _q
uery    conn.query(q)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 505, i
n query    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 724, i
n _read_query_result    result.read()
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 1069, 
in read    first_packet = self.connection._read_packet()
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 646, i
n _read_packet    packet_header = self._read_bytes(4)
  File "/root/test/venv/lib64/python3.6/site-packages/pymysql/connections.py", line 699, i
n _read_bytes    CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to
 MySQL server during query')[SQL: SELECT now();]
(Background on this error at: http://sqlalche.me/e/13/e3q8)

2. 解决方案

只需给 create_engine() 方法传入 pool_recycle 参数即可:

:param pool_recycle=-1: this setting causes the pool to recycle
        connections after the given number of seconds has passed. It
        defaults to -1, or no timeout. For example, setting to 3600
        means connections will be recycled after one hour. Note that
        MySQL in particular will disconnect automatically if no
        activity is detected on a connection for eight hours (although
        this is configurable with the MySQLDB connection itself and the
        server configuration as well).

        .. seealso::

            :ref:`pool_setting_recycle`

我们的测试脚本中设置了 MySQL 的会话级别 wait_timeout=3,所以这里我们传入 pool_recycle=1(比 wait_timeout 小即可) 让连接保持存活

import time

from sqlalchemy.engine import create_engine


url = 'mysql+pymysql://root:123456@127.0.0.1:3306/test'
engine = create_engine(url, pool_recycle=1)

query = 'SELECT now();'

while True:
    print('Query-01', engine.execute(query).fetchall())
    engine.execute('SET wait_timeout=3')  # set session variable `wait_timeout`
    time.sleep(5)
    print('Query-02', engine.execute(query).fetchall())

再次测试:

(venv) [root@aliyun test]# python test.py 
Query-01 [(datetime.datetime(2020, 12, 12, 11, 11, 59),)]
Query-02 [(datetime.datetime(2020, 12, 12, 11, 12, 4),)]
Query-01 [(datetime.datetime(2020, 12, 12, 11, 12, 4),)]
Query-02 [(datetime.datetime(2020, 12, 12, 11, 12, 9),)]
...
未经允许不得转载: LIFE & SHARE - 王颜公子 » SQLAlchemy Tutorial | Lost connection to MySQL server during query

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.