在查询期间失去与 MySQL 服务器的连接

我有一个巨大的表,我需要处理其中的所有行。我总是得到这个丢失连接消息,我不能重新连接和恢复光标到它的最后位置。这基本上就是我这里的代码:

#
import MySQLdb


class DB:
conn = None


def connect(self):
self.conn = MySQLdb.connect('hostname', 'user', '*****', 'some_table', cursorclass=MySQLdb.cursors.SSCursor)


def query(self, sql):
try:
cursor = self.conn.cursor()
cursor.execute(sql)
except (AttributeError, MySQLdb.OperationalError):
self.connect()
cursor = self.conn.cursor()
cursor.execute(sql)
return cursor
#


#
db = DB()
sql = "SELECT bla FROM foo"
data = db.query(sql)


for row in data:
do_something(row)
#

但我总是得到这个:

#
Traceback (most recent call last):
File "teste.py", line 124, in <module>
run()
File "teste.py", line 109, in run
for row in data:
File "/usr/lib64/python2.5/site-packages/MySQLdb/cursors.py", line 417, in next
row = self.fetchone()
File "/usr/lib64/python2.5/site-packages/MySQLdb/cursors.py", line 388, in fetchone
r = self._fetch_row(1)
File "/usr/lib64/python2.5/site-packages/MySQLdb/cursors.py", line 285, in _fetch_row
return self._result.fetch_row(size, self._fetch_type)
_mysql_exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query')
Exception _mysql_exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query') in <bound method SSCursor.__del__ of <MySQLdb.cursors.SSCursor object at 0x7f7e3c8da410>> ignored
#

你知道吗?

206834 次浏览

您需要增加连接的超时时间。如果出于某种原因,你不能或不想这么做,你可以试着打电话:

data = db.query(sql).store_result()

这将立即获取所有结果,这样您的连接就不会在迭代过程中超时。

Mysql 文档有一整个页面专门处理这个错误: Http://dev.mysql.com/doc/refman/5.0/en/gone-away.html

值得注意的是

  • 如果向服务器发送的查询不正确或过大,也可能会出现这些错误。如果 mysqld 接收到一个太大或无序的数据包,它会假设客户端出了问题并关闭连接。如果需要大型查询(例如,如果使用大型 BLOB 列) ,可以通过设置服务器的 max _ allow _ pack 变量来增加查询限制,该变量的默认值为1MB。您可能还需要增加客户端的最大数据包大小。关于设置数据包大小的更多信息见 B.5.2.10节“数据包太大”。

  • 通过使用—— log-police = 2选项启动 mysqld,您可以获得有关丢失的连接的更多信息。这将记录 hostname.err 文件中的一些断开连接的错误

请确保在连接之前关闭光标。我已经解决了这个问题:

if cur and con:
cur.close()
con.close()

将“ max _ allow _ pack”设置为64M 并重新启动 MySql 服务器。如果这没有解决你的问题,问题可能在别处。

我有一个多线程 PHP CLI 应用程序,它可以进行同步查询,我最近注意到了这个问题。现在对我来说很明显的是,MySql 服务器将来自同一 IP 的所有连接视为一个“单一”连接,因此每当一个查询完成时就会删除所有连接。

我想知道是否有一种方法可以让 MySql 允许来自同一个 IP 的100个连接,并将每个连接视为一个单独的连接。

有三种方法可以扩大 mysql 服务器的 max _ allow _ pack:

  1. 在 mysql 服务器机器上的 /etc/mysql/my.cnf文件中更改 max_allowed_packet=64M并重新启动服务器
  2. 在 mysql 服务器上执行 sql: set global max_allowed_packet=67108864;
  3. Python 在连接到 mysql 之后执行 sql:
connection.execute('set max_allowed_packet=67108864')

在分叉子进程的应用程序中也可能遇到此错误,所有这些应用程序都试图使用到 MySQL 服务器的相同连接。可以通过为每个子进程使用单独的连接来避免这种情况。

叉子可能会打到你,不过在这种情况下要小心。

这是发生在我身上的 Mariadb,因为我做了一个 varchar(255)专栏的 unique key。.我猜这对于一个独一无二的人来说太重了,因为插入的时间已经过了。

我对我的案件的原因

ERROR 2013(HY000) : 在查询期间与 MySQL 服务器失去连接

错误是我的表的一部分是 堕落。我也不能 mysqldump我的表,因为一些行打破了它。 这个错误与上面提到的内存问题等无关。

好在 MySQL 返回了第一个失败的行号。就像是

Mysqldump: 错误2013: 在转储行为12723的表 mytable 时,查询期间与 MySQL 服务器的连接丢失

解决方案是将数据复制到一个新表中。在我的例子中,我丢失了10行数据,因为我必须跳过这些损坏的行。首先,我使用旧的模式创建了一个“ tmp”表。SHOW CREATE TABLE是你的朋友。例如。

SHOW CREATE TABLE mydatabase.mytable;

用 i 创建了新的表。我们叫它 我的桌子。然后复制你能够通过例如复制的行。

insert into mysqltabletmp select * from mytable where id < 12723;
insert into mysqltabletmp select * from mytable where id > 12733;

在删除旧表之后,将 tmp-table 重命名为旧表名。

关于这个问题也有 彼得提供了一些有用的信息

如果某人或某事使用 杀戮指令中断了您的连接,也会发生这种情况。

当我试图更新一个磁盘上的大小大于可用磁盘空间的表时,发生了这种情况。对我来说,解决方案只是增加可用的磁盘空间。

在我的例子中,我在寻找 SQL 转储时遇到了这个问题,这个 SQL 转储将表放置在了错误的顺序中。有问题的 CREATE 包含一个 CONSTRINT... REFERENCES,它引用了一个尚未创建的表。

我定位了有问题的表,并将其 CREATE 语句移到了错误表的上方,错误消失了。

我遇到的与这个错误转储相关的另一个错误是 ERROR 1005/errno: 150——“ Can’t create table”,同样是因为创建表的顺序错误。

当我的 CONSTRAINT名称与其他 CONSTRAINT名称具有相同的名称时,就会发生这种情况。

改变我的 CONSTRAINT名字解决了这个问题。

我也遇到过类似的问题,在我的例子中,这个问题通过这样获取光标得到了解决:

cursor = self.conn.cursor(buffered=True)

多处理和 Django 数据库不能很好地结合在一起。

在新进程中,我最终关闭了 Django DB 连接。

这样就不会有对父级所使用的连接的引用。

from multiprocessing import Pool


multi_core_arg = [[1,2,3], [4,5,6], [7,8,9]]
n_cpu = 4
pool = Pool(n_cpu)
pool.map(_etl_, multi_core_arg)
pool.close()
pool.join()


def _etl_(x):
from django.db import connection
connection.close()
print(x)

或者

Process.start()调用一个函数,该函数以

其他人建议使用

from multiprocessing.dummy import Pool as ThreadPool

它解决了我的(2013,丢失连接)问题,但线程使用 GIL,当做 IO 时,将释放它当 IO 完成。

相比之下,Process 产生一组彼此通信的工作者,这可能比较慢。

我建议你计时。 一个小贴士是使用 即兴发挥,它是由 scikit-learn 项目支持的。 一些性能结果表明它比原生 Pool ()更优秀。.尽管它将验证真实运行时成本的责任留给了编码人员。

我也遇到了同样的问题。由于其他一些问题,我试图在其他函数中添加 cnx.close()行。取而代之的是,我删除了所有这些无关的关闭项,并像这样设置了我的类:

class DBase:


config = {
'user': 'root',
'password': '',
'host': '127.0.0.1',
'database': 'bio',
'raise_on_warnings': True,
'use_pure': False,
}


def __init__(self):
import mysql.connector
self.cnx = mysql.connector.connect(**self.config)
self.cur = self.cnx.cursor(buffered=True)
print(self.cnx)
def __enter__(self):
return DBase()


def __exit__(self, exc_type, exc_val, exc_tb):
self.cnx.commit()
if self.cnx:
self.cnx.close()

在这个类中调用的任何函数都是连接、提交和关闭的。

很容易解决,进入 phpadmin 的控制面板,点击 config/然后编辑。查看 ini 文件。如果端口3306不是您正在使用的端口,请查找该端口,以便将3306连接到您正在使用的端口。在您的登录屏幕上,只需为您的服务器放置 localhost,如果端口不是默认的,或者如果您没有在 sql 配置中更改文件名 my.ini,则保持不变。然后输入您的用户名: root 或您创建的用户名,然后输入密码: 1234或您分配的用户名。如果您正在连接本地,请不要选中 url 选项。然后键入要编辑的数据库的名称。注意: 一旦连接上,您将看到服务器上或正在连接的服务器上的数据库列表。

当我尝试使用数百万条记录进行批量插入时,由于“管道破裂”而出现了这个错误。我最终解决了这个问题,将我的数据分块成较小的批处理大小,然后使用 mysql 光标为我需要执行的每个插入运行 Executemany 命令。这解决了问题,而且似乎没有以任何明显的方式影响性能。

例如。

def chunks(data):
for i in range(0, len(data), CHUNK_SIZE):
yield data[i:i + CHUNK_SIZE]




def bulk_import(update_list):
new_list = list(chunks(update_list))
for batch in new_list:
cursor.execute(#SQL STATEMENT HERE)

与@imxylz 相同,但是我不得不使用 mycursor.execute('set GLOBAL max_allowed_packet=67108864'),因为我得到了一个只读错误,而没有使用 GLOBAL 参数。

mysql.connector.__version__

8.0.16

同样的情况也发生在我使用 mariadb sqlalchemypandas的时候,就像上面的 @iamapotatoe一样,我也创建了一个函数来将数据帧分解成块,然后一点一点地将它们移植到 sql 数据库中。 特别是在更改 mysql 配置选项中的 max_allowed_packet对您不起作用的情况下,可以利用这一点。

def load_large_df(table_name,df_to_load,batch_size,engine):
df_to_load = df_to_load.dropna(how='all')
with engine.connect() as conn:
conn.execute(f"DROP TABLE IF EXISTS {table_name}")
rows = df_to_load.shape[0]
batch = int(rows/batch_size)
        



strt = 0
while strt < rows:
df = df_to_load[strt:].head(batch)
df.to_sql(table_name,con=conn,if_exists='append')
strt += batch

你可以看到我对类似问题的回答如下:

Https://stackoverflow.com/a/69610550/16647254

用锁来解决这个问题

lock.acquire()
mysqlhelper.getconn()
result_db_num = mysqlhelper.update(sql, [businessid, md5_id])
mysqlhelper.end()
mysqlhelper.dispose()
lock.release()

我也遇到了同样的问题,我花了好几个小时来试验各种不同的解决方案。对我来说最终奏效的是这个。代码最初打开一个10个连接池,然后 mysql.connect 使用 get _ connect ()从池中提供连接。

class DB:
connection = None


def __init__(self):
self.conn()


def conn(self):
try:
if not self.connection:
self.connection = mysql.connector.pooling.MySQLConnectionPool(user='web', password='mypasswd',
host='prod', database='myelection',
autocommit=True, pool_size=10,
buffered=True)
return self.connection.get_connection()


except mysql.connector.errors.InterfaceError as err:
print("can't connect to mysql ", err)


except mysql.connector.DatabaseError as err:
print("database error: ", err)


except Exception as err:
print("unknown db exception: ", err)


print("exiting from conn() with error.")
exit()


# Make sure your class methods open, then automatically
# close the connections and the cursors.
def new_polling_place(self, pp_name):
#  cur = self.conn().cursor(dictionary=True)
with self.conn() as con:
with con.cursor() as cur:
cur.execute("INSERT INTO pollingplace (pp_name) VALUES (%s)", [pp_name])
return cur.lastrowid