我用pymysql在MySQL执行查询,为什么关闭连接后进程还在?
I use pymysql to execute query in MySQL, but why the process is still alive after I close the connection?
我使用pymysql
连接mysql,连接时我设置了一个read_timeout
:
conn = pymysql.connect(host=host,port=port,user=user,passwd=passwd,read_timeout=60)
我的查询代码在这里:
try:
cur.execute(sql)
rows = cur.fetchall()
except:
# timeout
logging.error()
finally:
cur.close()
conn.close()
当我执行长时间查询时,代码会引发超时错误,最后 cursor
和 connection
都关闭(我调试 conn._closed
以确认连接已关闭) .但是当我登录到mysql和show processlist
时,我发现进程还活着。
我的问题是,这是否正常?如何在我的代码中查询超时时终止进程?我想出了一个在查询之前执行 set session max_execution_time=60
的解决方法,但我认为这不是最佳做法。
这里是show processlist
输出,我用sleep
表示长时间查询,我想结果是一样的,connection
在我的代码中关闭了,但是进程还在那里。
show processlist output
您需要在关闭连接之前提交事务。由于事务尚未提交到数据库,因此该进程必须处于活动状态。
在开头或 conn
初始化期间添加 conn.autocommit=true
,
conn = pymysql.connect(host=host,port=port,user=user,passwd=passwd,read_timeout=60, autocommit=True)
或者,您可以在关闭连接之前使用conn.commit()
。
PyMySQL 连接对象上的 read_timeout
在执行 timeout value on the underlying socket during read operations. If the timeout is reached, the socket raises a subclass of OSError
(socket.timeout), which is caught in the connection's _read_bytes method.
During the handling of that exception, _force_close 时使用,最终将连接的 self._sock
属性设置为 None
。
当您的代码到达 finally
块时,在执行 conn.close()
期间剩下要做的就是将 _closed
设置为 True。
如果此时 _sock
不是 None
,close
方法也会尝试通过套接字将 COM_QUIT
发送到服务器,但是由于客户端套接字已经关闭,那不会发生。
从服务器的角度来看,客户端无声地断开了连接。不幸的是,很难找到有意义的文档来说明这种情况下到底发生了什么。
通常,在连接超时时,挂起的事务应该被回滚。但是,我不确定客户端关闭其套接字是否会导致服务器端立即超时,如 this Q&A 中所建议的那样。
此外,使用 MySQL 的 sleep
函数进行测试可能不是一个好主意。它可以完全挂起处理您的连接和查询的线程,使其无法及时检测到丢失的连接。
您可能想看看 MySQL 的 kill command, that is also implemented in the PyMySQL connection,尽管没有记录。但是,当执行 cursor.execute
语句可能需要很长时间才能完成时,这将需要在脚本中设置外部超时。
我使用pymysql
连接mysql,连接时我设置了一个read_timeout
:
conn = pymysql.connect(host=host,port=port,user=user,passwd=passwd,read_timeout=60)
我的查询代码在这里:
try:
cur.execute(sql)
rows = cur.fetchall()
except:
# timeout
logging.error()
finally:
cur.close()
conn.close()
当我执行长时间查询时,代码会引发超时错误,最后 cursor
和 connection
都关闭(我调试 conn._closed
以确认连接已关闭) .但是当我登录到mysql和show processlist
时,我发现进程还活着。
我的问题是,这是否正常?如何在我的代码中查询超时时终止进程?我想出了一个在查询之前执行 set session max_execution_time=60
的解决方法,但我认为这不是最佳做法。
这里是show processlist
输出,我用sleep
表示长时间查询,我想结果是一样的,connection
在我的代码中关闭了,但是进程还在那里。
show processlist output
您需要在关闭连接之前提交事务。由于事务尚未提交到数据库,因此该进程必须处于活动状态。
在开头或 conn
初始化期间添加 conn.autocommit=true
,
conn = pymysql.connect(host=host,port=port,user=user,passwd=passwd,read_timeout=60, autocommit=True)
或者,您可以在关闭连接之前使用conn.commit()
。
read_timeout
在执行 timeout value on the underlying socket during read operations. If the timeout is reached, the socket raises a subclass of OSError
(socket.timeout), which is caught in the connection's _read_bytes method.
During the handling of that exception, _force_close 时使用,最终将连接的 self._sock
属性设置为 None
。
当您的代码到达 finally
块时,在执行 conn.close()
期间剩下要做的就是将 _closed
设置为 True。
如果此时 _sock
不是 None
,close
方法也会尝试通过套接字将 COM_QUIT
发送到服务器,但是由于客户端套接字已经关闭,那不会发生。
从服务器的角度来看,客户端无声地断开了连接。不幸的是,很难找到有意义的文档来说明这种情况下到底发生了什么。
通常,在连接超时时,挂起的事务应该被回滚。但是,我不确定客户端关闭其套接字是否会导致服务器端立即超时,如 this Q&A 中所建议的那样。
此外,使用 MySQL 的 sleep
函数进行测试可能不是一个好主意。它可以完全挂起处理您的连接和查询的线程,使其无法及时检测到丢失的连接。
您可能想看看 MySQL 的 kill command, that is also implemented in the PyMySQL connection,尽管没有记录。但是,当执行 cursor.execute
语句可能需要很长时间才能完成时,这将需要在脚本中设置外部超时。