问题记录:当持有mysql连接实例但一直闲置直到超过了wait_timeout时

96 阅读1分钟

报错如下:

(0, '')

分析:

在网上搜了这个报错,是说因为mysql client的连接实例虽然还在,但因为clientserver已经太久没有通信,所以server已经把连接关了,所以client连不上了。也就是如果不用的时候就应该把连接关掉才对,这种不合理的闲置连接超出了serverwait_timeout时间。

代码里是因为在循环里该break的地方写成continue了,就没有适时地释放对象、关闭连接。。

复现:

  1. 启动本地mysql server image.png

  2. 设置wait_timeout=10(默认值是28800

import pymysql.cursors

connect = pymysql.Connect(host='127.0.0.1', user='root', passwd='root')
cursor = connect.cursor()
# set value to 10
cursor.execute("set global wait_timeout = 10")
connect.close()

connect = pymysql.Connect(host='127.0.0.1', user='root', passwd='root')
cursor = connect.cursor()
cursor.execute("show variables like 'wait_timeout'")
ret_wait = cursor.fetchone()
print(f"after change: {ret_wait}")
  1. 模拟在循环里持有数据库连接并闲置超过10秒,然后再查数据库,就看到了这个报错
import time
import pymysql


class DBHelper:
    def __init__(self, host, user, passwd, port=3306):
        print('DBHelper init')
        self.db = pymysql.Connect(host=host, port=port, user=user, passwd=passwd)

    def query(self, sql):
        try:
            cursor = self.db.cursor()
            cursor.execute(sql)
            rows = cursor.fetchall()
        except Exception as e:
            raise e
        else:
            return rows


class QueryWrapper:
    def __init__(self):
        self.mars6_db = DBHelper(
            '127.0.0.1',
            'root',
            'root'
            # port is default to 3306
        )

    def query_test(self):
        try:
            sql = f"select id from test.person where id=1;"
            rows = self.mars6_db.query(sql)
            return rows[0][0]
        except Exception as e:
            print(f"query_test error, {e}")
            return -1


class Slave:
    def __init__(self):
        self.utils = QueryWrapper()

    def problem(self):
        count = 15
        while True:
            time.sleep(1)
            count -= 1
            try:
                if count > 0:
                    print('no task...')
                    time.sleep(1)
                    continue  # SHOULD break here

                r = self.utils.query_test()
                print(f'task result: {r}')
            except Exception as e:
                print(e)
                break


def job():
    daily_classifier_slave = Slave()
    daily_classifier_slave.problem()


if __name__ == '__main__':
    while True:
        job()
        print('sleep...')
        time.sleep(5)

Untitled.png