基于mysql连接池的pymysql
pymysql-pool的Python项目详细描述
pymysql连接池
一个简单的基于pymysql的连接池。主要集中在多线程模式时使用pymysql
,也兼容单线程模式,方便您在需要同时使用这两种模式时使用。在多线程模式下支持复用类似的特性(当使用与{{CD2}}连接时)。
问题:在python多线程中使用pymysql时,通常会遇到以下问题:
- 它不能与所有子线程共享由主线程创建的连接。它将导致如下错误:
pymysql.err.InternalError: Packet sequence number wrong - got 0 expected 1
- 如果我们让每个子线程创建一个连接,并在这个子线程结束时关闭它,这是可行的,但显然会导致与mysql建立连接的高成本。
因此,我实现这个模块的目的是在多线程编程中尽可能少地创建与mysql的连接。
本模块包含两个类:
Connection
是pymysql.connections.Connection
的一个子类,它可以使用连接池,也可以不使用连接池,它的用法与pymysql完全相同。有关连接池的详细信息(当使用连接池时,应该采取其他操作来维护该池)被隐藏。
为了方便起见,这个类提供了一个包装的execute_query()方法,该方法接受几个参数。ConnectionPool
的实例表示真正的连接池。
使用示例
安装
pip install pymysql-pool
多线程模式:
与单线程模式的主要区别在于我们应该保持池的状态。例如“从池获取连接”或“将连接放回池”,在这种情况下,还需要处理一些情况,例如:
- 从池获取连接时:我们应该处理timeout和retry参数
- 将连接放回池:如果执行查询时没有异常,则此连接可以直接返回池;但如果发生exception,则应根据此连接是否可reusable(基于异常类型)来决定是否应返回池。如果连接不应该返回到池,我们将其关闭并重新创建一个新连接,然后将其放到池中。
幸运的是,这个模块会自动处理这些复杂的细节。
还可以创建多个连接池(具有不同的ConnectionPool.name
属性)以与不同的数据库关联。
在下面的示例中,我们将看到它如何在连接池功能中工作:
>>> import pymysqlpool
>>> pymysqlpool.logger.setLevel('DEBUG')
>>> config={'host':'xxxx', 'user':'xxx', 'password':'xxx', 'database':'xxx', 'autocommit':True}
### Create a connection pool with 2 connection in it
>>> pool1 = pymysqlpool.ConnectionPool(size=2, name='pool1', **config)
>>> pool1.size()
2
>>> con1 = pool1.get_connection()
2017-12-25 21:38:48 DEBUG: Get connection from pool(pool1)
>>> con2 = pool1.get_connection()
2017-12-25 21:38:51 DEBUG: Get connection from pool(pool1)
>>> pool1.size()
0
### We can prophesy that here will occur some exception, because the pool1 is empty
>>> con3 = pool1.get_connection(timeout=0, retry_num=0)
Traceback (most recent call last):
File "e:\github\pymysql-pool\pymysqlpool.py", line 115, in get_connection
conn = self._pool.get(timeout=timeout) if timeout > 0 else self._pool.get_nowait()
queue.Empty
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
con3 = pool1.get_connection(timeout=0, retry_num=0)
File "e:\github\pymysql-pool\pymysqlpool.py", line 128, in get_connection
self.name, timeout, total_times))
pymysqlpool.GetConnectionFromPoolError: can't get connection from pool(pool1) within 0*1 second(s)
### Now let's see the connection's behavior when call close() method and use with Context Manager Protocol
>>> con1.close()
2017-12-25 21:39:56 DEBUG: Put connection back to pool(pool1)
>>> with con1 as cur:
cur.execute('select 1+1')
1
2017-12-25 21:40:25 DEBUG: Put connection back to pool(pool1)
### We can see that the module maintain the pool appropriate when(and only when) we call the close() method or use the Context Manager Protocol of connection object.
注意1:我们应该始终使用连接对象的close()方法或上下文管理器协议之一,否则池将很快耗尽。
{STR 1 } $注2:< /强>上下文管理器协议是首选的,它可以实现“复用”类似的效果。
注意3:使用close()方法时,注意不要多次使用连接对象的close()方法(您知道为什么~)。