Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x Python 3中mariadb连接长时间不活动后发生mariadb.DatabaseError_Python 3.x_Exception_Mariadb - Fatal编程技术网

Python 3.x Python 3中mariadb连接长时间不活动后发生mariadb.DatabaseError

Python 3.x Python 3中mariadb连接长时间不活动后发生mariadb.DatabaseError,python-3.x,exception,mariadb,Python 3.x,Exception,Mariadb,所以我正在开发这个类似telnet的在线游戏,但它不是很受欢迎(谁知道,有一天),所以我的游戏引擎的数据库连接在晚上几个小时内都不用。它是一个等待事件的脚本,因此它会继续运行 在数小时不活动后第一次执行查询时,我在尝试执行游标时收到mariadb.DatabaseError。如果我重做查询,它会再次工作。因此,当函数抛出连接丢失的异常时,它会修复连接 我的问题:我应该如何处理 这些是我认为可能的解决方案,但在我看来,它们不是很好: 将每个查询包装在一个try-except结构中,会使代码变得庞

所以我正在开发这个类似telnet的在线游戏,但它不是很受欢迎(谁知道,有一天),所以我的游戏引擎的数据库连接在晚上几个小时内都不用。它是一个等待事件的脚本,因此它会继续运行

在数小时不活动后第一次执行查询时,我在尝试执行游标时收到mariadb.DatabaseError。如果我重做查询,它会再次工作。因此,当函数抛出连接丢失的异常时,它会修复连接

我的问题:我应该如何处理

这些是我认为可能的解决方案,但在我看来,它们不是很好:

  • 将每个查询包装在一个try-except结构中,会使代码变得庞大,其中包含大量不必要和重复的代码
  • 编写我自己的“decorator”函数来执行查询,当我得到mariadb.DatabaseError时,它将重新初始化数据库,这似乎更好,但使我能够围绕(几乎)完美工作的库函数编写包装函数
  • 每N分钟执行一次几乎毫无意义的“ping”查询,这会给数据库带来压力,99.9%的时间都是无用的
下面是一些代码来说明:

import mariadb
class Db:
  ...
  def __init__(self):
    self.conn = mariadb.connect(user=self.__db_user, password=self.__db_pass, host=self.__db_host, port=self.__db_port, database=self.__db_name)

  def one_of_many_functions(self, ...):
    cur = self.conn.cursor()
    cur.execute('SELECT ...') # Here is where the mariadb.DatabaseError happens after long inactivity, and otherwise runs fine
    ...
我真的不明白为什么python的mariadb实现不能处理这个问题。当连接丢失时,cur.execute将抛出mariadb.DatabaseError,但不采取任何操作,因为如果我使用相同的数据库连接重新查询,它将再次工作。因此,连接会自我修复。为什么组件在“修复”连接本身并可以再次查询时让我重新查询


但事实上,我的问题是:处理这个问题最好的方法是什么?

您是使用套接字还是TCP/IP进行连接

TCP/IP连接被设计为在一段时间没有流量后进行清理。你可能会说这很愚蠢,但是没有更好的方法知道程序是否崩溃了

出于同样的原因,数据库有自己的超时机制。对于MySQL,它被称为

通常,连接对象(或其包装器)将负责运行一些无操作查询,如果连接没有其他情况发生,例如
select 1
。这是一种标准做法。检查您的连接对象的文档-它可能已经存在,您只需要配置它。使用大约30-60秒


如果没有,您将不得不自己实施它。不管怎样,关键是你不能期望连接永远保持开放。要么让连接短命(只在需要时打开,然后关闭),要么实现一个计时器,定期插入一些无操作查询。在后一种情况下,请注意,您需要实现同步机制,以确保应用程序查询不会与无操作查询同时运行。

您是否使用套接字或TCP/IP进行连接

TCP/IP连接被设计为在一段时间没有流量后进行清理。你可能会说这很愚蠢,但是没有更好的方法知道程序是否崩溃了

出于同样的原因,数据库有自己的超时机制。对于MySQL,它被称为

通常,连接对象(或其包装器)将负责运行一些无操作查询,如果连接没有其他情况发生,例如
select 1
。这是一种标准做法。检查您的连接对象的文档-它可能已经存在,您只需要配置它。使用大约30-60秒


如果没有,您将不得不自己实施它。不管怎样,关键是你不能期望连接永远保持开放。要么让连接短命(只在需要时打开,然后关闭),要么实现一个计时器,定期插入一些无操作查询。在后一种情况下,请注意,您需要实现同步机制,以确保应用程序查询不会与无操作查询同时运行。

您是否考虑过使用连接池

# Create Connection Pool
pool = mariadb.ConnectionPool(
      #...,
      pool_size=1
   )

然后在你的连接方法

try:
    pconn = pool.get_connection()

except mariadb.PoolError as e:
   # Report Error
   print(f"Error opening connection from pool: {e}")
文档没有说明当连接关闭或断开时会发生什么。我希望它能解决这个问题,并始终尝试提供有效的连接(只要您不要求比池中更多的连接)


我从

获得了代码。您是否考虑过使用连接池

# Create Connection Pool
pool = mariadb.ConnectionPool(
      #...,
      pool_size=1
   )

然后在你的连接方法

try:
    pconn = pool.get_connection()

except mariadb.PoolError as e:
   # Report Error
   print(f"Error opening connection from pool: {e}")
文档没有说明当连接关闭或断开时会发生什么。我希望它能解决这个问题,并始终尝试提供有效的连接(只要您不要求比池中更多的连接)


我从

中获得了代码如果您设置了一个长超时值,甚至不能保证连接会由于其他原因(客户端超时、24小时断开连接等)而断开

一个选项是设置自动重新连接,如下例所示:

import mariadb

conn1= mariadb.connect()
conn2= mariadb.connect()

# Force MariaDB/Connector Python to reconnect
conn2.auto_reconnect= True

cursor1= conn1.cursor()

print("Connid of connection 2: %s" % conn2.connection_id);

# Since we don't want to wait, we kill the conn2 intentionally
cursor1.execute("KILL %s" % conn2.connection_id)

cursor2= conn2.cursor()
cursor2.execute("select connection_id()")
row= cursor2.fetchall()
print("Connid of connection 2: %s" % conn2.connection_id);
print(row)
输出:

Connid of connection 2: 174
Connid of connection 2: 175
[(175,)]

因此,在连接2被终止后,next cursor.execute将在执行语句之前建立一个新的连接。如果使用现有的打开游标,此解决方案将不起作用,因为内部语句句柄将无效。

如果设置长超时值,甚至不能保证连接会由于其他原因(客户端超时、24小时断开连接等)而断开

一个选项是设置自动重新连接,如下例所示:

import mariadb

conn1= mariadb.connect()
conn2= mariadb.connect()

# Force MariaDB/Connector Python to reconnect
conn2.auto_reconnect= True

cursor1= conn1.cursor()

print("Connid of connection 2: %s" % conn2.connection_id);

# Since we don't want to wait, we kill the conn2 intentionally
cursor1.execute("KILL %s" % conn2.connection_id)

cursor2= conn2.cursor()
cursor2.execute("select connection_id()")
row= cursor2.fetchall()
print("Connid of connection 2: %s" % conn2.connection_id);
print(row)
输出:

Connid of connection 2: 174
Connid of connection 2: 175
[(175,)]

因此,在连接2被终止后,next cursor.execute将在执行语句之前建立一个新的连接。如果使用现有的打开游标,此解决方案将不起作用,因为内部语句句柄将变得无效。

我真的不想在每个查询周围写一个try-excet块,并在它周围写一个while循环来重试,直到它起作用为止。。。阿尔索