【问题标题】:What is the best solution for database connection pooling in python?python中数据库连接池的最佳解决方案是什么?
【发布时间】:2010-09-11 01:15:12
【问题描述】:

我开发了一些自定义的类似 DAO 的类来满足我的项目的一些非常特殊的要求,我的项目是一个不在任何类型的框架内运行的服务器端进程。

该解决方案效果很好,只是每次发出新请求时,我都会通过 MySQLdb.connect 打开一个新连接。

将其切换为在 python 中使用连接池的最佳“直接”解决方案是什么?我正在想象类似 Java 的 commons DBCP 解决方案。

该进程运行时间很长,并且有许多线程需要发出请求,但不是同时发出请求……特别是在短暂地写出大量结果之前,它们会做很多工作。

编辑添加: 经过更多搜索后,我发现anitpool.py 看起来不错,但由于我对python 比较陌生,我想我只是想确保我不会错过更明显/更惯用/更好的解决方案。

【问题讨论】:

    标签: python mysql connection-pooling


    【解决方案1】:

    我一直在寻找同样的东西。

    我找到了pysqlpoolsqlalchemy pool module

    【讨论】:

      【解决方案2】:

      IMO,“更明显/更惯用/更好的解决方案”是使用现有的 ORM,而不是发明类似 DAO 的类。

      在我看来,ORM 比“原始”SQL 连接更受欢迎。为什么?因为Python OO,而从SQL 行到对象的映射 是绝对必要的。处理不映射到 Python 对象的 SQL 行的用例并不多。

      我认为SQLAlchemySQLObject(以及相关的连接池)是更惯用的 Pythonic 解决方案。

      将池作为一项单独的功能并不常见,因为纯 SQL(没有对象映射)对于受益于连接池的复杂、长时间运行的进程来说并不是很受欢迎。是的,使用纯 SQL ,但它总是用于更简单或更受控制的应用程序,而池化没有帮助。

      我认为您可能有两种选择:

      1. 修改您的类以使用 SQLAlchemy 或 SQLObject。虽然这起初看起来很痛苦(所有工作都被浪费了),但您应该能够利用所有的设计和思想。这只是采用广泛使用的 ORM 和池化解决方案的练习。
      2. 使用您概述的算法推出您自己的简单连接池 - 您循环通过的简单连接集或列表。

      【讨论】:

        【解决方案3】:

        使用DBUtils,简单可靠。

        pip install DBUtils
        

        【讨论】:

          【解决方案4】:

          回复旧线程但我上次检查时,MySQL 提供连接池作为其驱动程序的一部分。

          您可以在以下位置查看它们:

          https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html

          来自 TFA,假设您要显式打开连接池(如 OP 所述):

          dbconfig = {  "database": "test", "user":"joe" }
          cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name = "mypool",pool_size = 3, **dbconfig)
          

          然后通过 get_connection() 函数从池中请求访问该池。

          cnx1 = cnxpool.get_connection()
          cnx2 = cnxpool.get_connection()
          

          【讨论】:

            【解决方案5】:

            包装你的连接类。

            限制您建立的连接数。 返回一个未使用的连接。 拦截关闭以释放连接。

            更新: 我在 dbpool.py 中放了这样的东西:

            import sqlalchemy.pool as pool
            import MySQLdb as mysql
            mysql = pool.manage(mysql)
            

            【讨论】:

            • 克里斯,肯定有人已经建造了这个吗?最坏的情况是我可以自己编写,但显然这对于​​不使用现有 ORM/框架的人来说应该是一个相当普遍的要求,而且我确信其他人已经创建了一个经过时间证明的解决方案?
            • 我以前用 Oracle 做过这个,我认为它总共涉及不到 50 行代码。基本上就是使用一个id、字典、存储连接、存储使用状态等。很简单吗?
            • @Chris,按照这个逻辑链,我也应该开始自己实现我的哈希图和列表。
            【解决方案6】:

            旧线程,但对于通用池(连接或任何昂贵的对象),我使用类似的东西:

            def pool(ctor, limit=None):
                local_pool = multiprocessing.Queue()
                n = multiprocesing.Value('i', 0)
                @contextlib.contextmanager
                def pooled(ctor=ctor, lpool=local_pool, n=n):
                    # block iff at limit
                    try: i = lpool.get(limit and n.value >= limit)
                    except multiprocessing.queues.Empty:
                        n.value += 1
                        i = ctor()
                    yield i
                    lpool.put(i)
                return pooled
            

            哪个是惰性构造,有一个可选的限制,并且应该推广到我能想到的任何用例。当然,这假设您确实需要任何资源的池化,而对于许多现代 SQL 类您可能不需要。用法:

            # in main:
            my_pool = pool(lambda: do_something())
            # in thread:
            with my_pool() as my_obj:
                my_obj.do_something()
            

            这确实假定 ctor 创建的任何对象都具有适当的析构函数(如果需要)(某些服务器不会终止连接对象,除非它们被显式关闭)。

            【讨论】:

            • 你忘记了两件事:1. yield i 可能会引发异常,所以你应该用 try...except 来包装它。 2.lpool.put(i) 可能会返回错误状态的对象(如打开事务的数据库连接)
            • 异常产生实际上应该由上下文管理器处理。无论上下文如何退出(异常或其他),函数的其余部分都将运行。但是,是的,如果您正在对数据库进行有状态操作,那么在函数的 post-yield 位中进行处理将是一个好主意。
            • 在实践中,使用 Chris 编辑过的帖子中的池对象可能会更好,但对于那些希望学习如何实现池的人来说,我认为这是一个很好的例子。
            【解决方案7】:

            如果您的应用决定开始使用多线程,那么创建自己的连接池是个坏主意。为多线程应用程序创建连接池比为单线程应用程序创建连接池要复杂得多。在这种情况下,您可以使用 PySQLPool 之类的东西。

            如果您正在寻找性能,使用 ORM 也是一个坏主意。

            如果您要处理必须处理大量选择、插入、 同时更新和删除,那么您将需要性能,这意味着您需要编写自定义 SQL 来优化查找和锁定时间。使用 ORM,您通常没有这种灵活性。

            所以基本上,是的,您可以创建自己的连接池并使用 ORM,但前提是您确定不需要我刚才描述的任何内容。

            【讨论】:

              【解决方案8】:

              在 MySQL 中?

              我想说不要打扰连接池。它们通常是麻烦的根源,并且对于 MySQL,它们不会为您带来您希望的性能优势。这条路可能需要付出很多努力——政治上——因为在这个领域有很多关于连接池优势的最佳实践和教科书式的冗长。

              连接池只是无状态应用程序(例如 HTTP 协议)的后 Web 时代和有状态的长寿命批处理应用程序的前 Web 时代之间的桥梁。由于前 Web 数据库中的连接非常昂贵(因为过去没有人关心建立连接需要多长时间),后 Web 应用程序设计了这种连接池方案,以便每次点击都不会产生如此巨大的处理开销在 RDBMS 上。

              由于 MySQL 更像是 Web 时代的 RDBMS,因此连接非常轻量级和快速。我为 MySQL 编写了许多根本不使用连接池的大容量 Web 应用程序。

              只要没有政治障碍需要克服,您可能会受益于不这样做的并发症。

              【讨论】:

              • 此答案发布 8 年后,池化继续保持相关性。如果你运行一个流量很大的 webapp,你很容易遇到“连接太多”的限制,不管它是无状态的。池将通过等待空闲连接而不是硬故障来帮助缓解这种情况。此外,如果您想水平扩展您的应用服务器,您的数据库可能不会在同一台机器上运行。在这种情况下,您很可能希望通过 HTTPS 连接到它,这会产生很大的开销。游泳池在这里也有帮助。
              猜你喜欢
              • 2017-06-26
              • 1970-01-01
              • 1970-01-01
              • 2011-05-13
              • 2010-11-02
              • 1970-01-01
              • 1970-01-01
              • 2011-03-20
              • 2013-05-01
              相关资源
              最近更新 更多