Skip to content

MySQL中的“Too many connections”的原因

问题分析

首先,我认为存在即为合理。这种提示并非说是MySQL的问题,而是我们程序的问题。
我举一个简单的例子,在很多爬虫项目中,我曾尝试使用PyMySQL来创建MySQL连接来进行相关的数据库操作。这样看着似乎没有什么问题,但当使用多线程以后,会发现原本创建的连接无法使用。这是因为:在PEP249中,相关线程安全的描述如下:

threadsafety Meaning
0 Threads may not share the module.
1 Threads may share the module, but not connections.
2 Threads may share the module and connections.
3 Threads may share the module, connections and cursors.

我们可以得知,在标志为1时,线程之间可以共享模块,但无法共享连接。也就意味着我们的每一个线程连接数据库时,都需要创建相应的连接。

但这样就结束了么?

import pymysql.cursors

config = {
    'host': '127.0.0.1',
    'port': 3306,
    'user': 'root',
    'password': 'root',
    'db': 'test',
    'charset': 'utf8',
}

while True:
    connection = pymysql.connect(**config)
    # do something
    connection.close()

貌似这么写是结束了,但是不久就会出现我们题目中所提到的问题->Too many connections.

这是为什么?

对,我也有怀疑,为什么我分明关闭了连接(connection.close()),为什么还会出现这种错误? 这个问题的答案就是,程序关闭了连接,而服务端并没有关闭。
怎么证明?

# 使用root登陆MySQL
show global variables like 'wait_timeout';

# 得到如下的信息
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

这便就是MySQL的默认的超时时间,即8个小时(单位是秒)。在查询结束后,将连接置于sleep状态,即使不存在网络等其他因素的问题,也不能允许客户端长久的建立连接,即超过8小时候,MySQL服务端主动关闭连接。 官方描述:

wait_timeout:The number of seconds the server waits for activity on a noninteractive connection before closing it. On thread startup, the session wait_timeout value is initialized from the global wait_timeout value or from the global interactive_timeoutvalue, depending on the type of client (as defined by the CLIENT_INTERACTIVE connect option to mysql_real_connect()).

科学合理的解决

我想,这就是使用ORM的一个原因了。