这是最近在做后台时碰到的:
OperationalError: (2013, 'Lost connection to MySQL server during query')
环境是 webpy + Apache + MySQL
这个问题麻烦之处在于它不是定期必然出现的,一般是运行了几个小时 或者 几天出现
出了这个 2013 错误以后,接下来的查询都会是:
OperationalError: (2006, 'MySQL server has gone away')
其实这个时候 MySQL Server 应该是没有挂的,
用客户端程序连接,但是看到里面 MySQLdb 的进程, 一直都是Sleep状态,即使那边一直在报错
这个问题可以通过重启 Apache 来缓解,但是不能预计下一次又会是什么时候出现
在网上搜索这两个Error,发现有很多人都有这个问题,但似乎没有一个好的解决方法
而出现这个问题的原因也是各种各样,比较流行的说法是
MySQL 的参数 wait_timeout 默认为28800=8小时,如果空闲超过了8小时 就会出现 Error 2006
但是我的 Server 应该是每分钟都会有连接过来进行数据库查询的,
不管怎么说还是把这个 wait_timeout 设置成 28800000 差不多1个月该够了吧?
但是好象没有效果
还有一种解决方法是在每次连接数据库前 ping 一下,如果连接已经断开,它会重新connect
这个也是针对Error 2006的,对我这种情况没有效果
后来在 MySQLdb 的 User‘s Guide上看到一段话:
The general upshot of this is: Don't share connections between threads. It's really not worth your effort or mine, and in the end, will probably hurt performance, since the MySQL server runs a separate thread for each connection. You can certainly do things like cache connections in a pool, and give those connections to one thread at a time. If you let two threads use a connection simultaneously, the MySQL client library will probably upchuck and die. You have been warned.
似乎 MySQLdb的多线程使用同一个连接会有点问题,
我用的 WEB 环境是 Apache + webpy(mod_wsgi),
MySQLdb是在模块中初始化的,不知道这样算不算是多线程共用一个数据库连接,
现在通过连接池 DBUtils 来管理数据库连接,服务器运行了3天,暂时还没出现那些数据库连接问题。
需要注意的是,使用DBUtils一些查询结果必须得保存起来,应为连接会被重用
比如:
value = conn.cursor.fetchall()[0]["field"]
要改成:
cur=conn.cursor
rs = cur.fetchall()
r = re[0]
value = r["field"]
PS:
又发现一个问题:
如果用 DBUtils,每次查询它都会到连接池找一个可用的连接
那么 select LAST_INSERT_ID(); 可就要小心了,这个是和连接相关的
我的解决方法是把 insert 和 select LAST_INSERT_ID(); 放到 FUNCTION 中
CREATE FUNCTION `func`(value int(11)) RETURNS int(11)
BEGIN
INSERT INTO table(field) VALUES (value);
RETURN LAST_INSERT_ID();
END;