【问题标题】:How to initialize a database connection only once and reuse it in run-time in python?如何只初始化一次数据库连接并在python的运行时重用它?
【发布时间】:2021-09-11 18:20:13
【问题描述】:

我目前正在从事一个大型项目,该项目不断执行查询。我的问题是,我的旧代码总是创建一个新的数据库连接和游标,这大大降低了速度。所以我想是时候做一个新的数据库类了,目前看起来是这样的:

class Database(object):

   _instance = None

   def __new__(cls):
      if cls._instance is None:
         cls._instance = object.__new__(cls)
         try:
            connection = Database._instance.connection = mysql.connector.connect(host="127.0.0.1", user="root", password="", database="db_test")
            cursor = Database._instance.cursor = connection.cursor()
         except Exception as error:
            print("Error: Connection not established {}".format(error))
         else:
            print("Connection established")
      return cls._instance
    
   def __init__(self):
      self.connection = self._instance.connection
      self.cursor = self._instance.cursor
   
   # Do database stuff here

查询将使用这样的类:

def foo():
   with Database() as cursor:
      cursor.execute("STATEMENT")

我不确定,无论创建类的频率如何,这是否只创建一次连接。也许有人知道如何只初始化一次连接以及之后如何在课堂上使用它,或者可能知道我的解决方案是否正确。感谢您的帮助!

【问题讨论】:

  • 你真的不需要__new__。只需在__init__ 和其他方法中使用Database.connection 而不是self.connection。
  • @TimRoberts 但是如果我的类不包含连接,我怎么能使用Database.connection,因为__new__ 方法创建了它?也许我错过了一些东西,如果你能向我解释一下就好了!已经谢谢你了!

标签: python database class


【解决方案1】:

有点像这样。这是一种使用全局变量的廉价方式。

class Database(object):
   connection = None

   def __init__(self):
      if not Database.connection:
         Database.connection = mysql.connector.connect(host="127.0.0.1", user="root", password="", database="db_test")

   def query(self,sql):
      cursor = Database.connection.cursor()
      cursor.execute(sql)
   
   # Do database stuff here

【讨论】:

  • 你的意思是这是便宜的方法,所以我认为还有更好的方法来解决我的问题?此解决方案是否也适用于我的问题中所示的 quieres 中的类使用?非常感谢你,你已经帮了我很多!
  • 当我这样做时,我通常将数据库连接存储在全局中,但将其存储在这样的类成员中可以提供更好的封装。
  • 很高兴知道,但由于无论如何我只使用类,我不需要将连接作为全局变量。非常感谢您的帮助!
  • 我可以提高我的程序的速度然后我像你对连接一样声明光标吗?所以它不会为每个查询创建一个新的,对吧?
  • 创建游标基本上不需要任何时间。重用它们几乎没有意义。创建连接非常昂贵,因此缓存它们是明智的。
【解决方案2】:

说明

这里的关键字显然是类变量。看一下official documentation,我们可以看到,除了实例变量之外,所有类实例都共享类变量,而不管类实例有多少。

一般来说,实例变量是针对每个实例唯一的数据,类变量是针对类的所有实例共享的属性和方法:

所以让我们假设您有 多个 类的实例。类本身的定义如下。

class Dog:
   
   kind = "canine"          # class variable shared by all instances

   def __init__(self, name):
      self.name = name      # instance variable unique to each instance

为了更好的理解类变量和实例变量的区别,我想在这里举个小例子:

>>> d = Dog("Fido")
>>> e = Dog("Buddy")
>>> d.kind   # shared by all dogs
"canine"
>>> e.kind   # shared by all dogs
"canine"
>>> d.name   # unique to d
"Fido"
>>> e.name   # unique to e
"Buddy"

解决方案

现在我们知道类变量由类的所有实例共享,我们可以简单地定义连接和游标,如下所示。

class Database(object):

   connection = None
   cursor = None

   def __init__(self):
      if Database.connection is None:
         try:
            Database.connection = mysql.connector.connect(host="127.0.0.1", user="root", password="", database="db_test")
            Database.cursor = Database.connection.cursor()
         except Exception as error:
            print("Error: Connection not established {}".format(error))
         else:
            print("Connection established")

      self.connection = Database.connection
      self.cursor = Database.cursor

因此,与数据库的连接在开始时创建一次,然后可以被以后的每个实例使用。

【讨论】:

    【解决方案3】:

    这也有效,保证您始终拥有一个数据库实例

    def singleton(class_):
        instances = {}
    
        def get_instance(*args, **kwargs):
            if class_ not in instances:
                instances[class_] = class_(*args, **kwargs)
            return instances[class_]
        return get_instance
    
    @singleton
    class SingletonDatabase:
        def __init__(self) -> None:
            print('Initializing singleton database connection... ', random.randint(1, 100))
    

    【讨论】:

      【解决方案4】:

      你必须做这一切的原因是如果你只是创造 一次连接,然后将其留在那里 最终会尝试使用被丢弃的连接

      因此您创建一个连接并将其附加到您的应用 然后每当您收到新请求时,请检查连接是否 仍然存在,如果没有请求钩子,则重新创建 连接并继续。

      on create_app
      
          def create_app(self):
      
              if not app.config.get('connection_created'):
                  app.database_connection = Database()
                  app.config['connection_created'] = True
      
      
      on run app
      
      
          @app.before_request
          def check_database_connection(self):
              if not app.config.get('connection_created') or not app.database_connection:
                  app.database_connection = Database()
                  app.config['connection_created'] = True
      

      这将确保您的应用程序始终以活动连接运行 并且每个应用只创建一次

      如果在任何后续调用中断开连接,则它会再次重新创建...

      【讨论】:

      • 可以理解,但是你从哪里得到app 变量,因为我的项目没有这样的变量?我猜您正在使用像 Flask 这样的模块,但是由于我的项目没有,因此无法实现您的解决方案。我说的对吗?
      猜你喜欢
      • 1970-01-01
      • 2020-09-08
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 2022-12-07
      • 2020-07-16
      相关资源
      最近更新 更多