`
phyeas
  • 浏览: 164678 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

设计Python数据库连接池1-对象的循环引用问题

阅读更多

在Python中如果对象定义了__del__方法的话,在对象的引用记数为0时会自动调用__del__方法(很象c++中的析构函数),但如果A对象引用B对象,B对象又引用A对象,就形成循环引用,此时A,B对象引用次数都为1。python就无法正常调用__del__方法,原计划在__del__方法里释放的资源自然也就无法释放。

一个连接池拥有多个连接,而每个连接又拥有这个连接池的实例(一个叫pool的属性)。这样就产生了刚刚说的哪个问题。我想到的办法就是在每次从池中获取连接的时候将连接的pool设置为当前实例,然后在归还这个连接的时候再将其设置为None,并且要在这个连接对象的__del__方法中将pool属性设置为None。具体看代码吧。(目前只实现了SQLite3的)

'''
Created on 2009-4-17

@author: phyeas
'''
import time
from queue import Queue

class PoolException(Exception):
    pass

class Pool(object):
    '''一个数据库连接池'''
    def __init__(self, maxActive=5, maxWait=None, init_size=0, db_type="SQLite3", **config):
        self.__freeConns = Queue(maxActive)
        self.maxWait = maxWait
        self.db_type = db_type
        self.config = config
        if init_size > maxActive:
            init_size = maxActive
        for i in range(init_size):
            self.free(self._create_conn())
    
    def __del__(self):
        print("__del__ Pool..")
        self.release()
    
    def release(self):
        '''释放资源,关闭池中的所有连接'''
        print("release Pool..")
        while self.__freeConns and not self.__freeConns.empty():
            con = self.get()
            con.release()
        self.__freeConns = None

    def _create_conn(self):
        '''创建连接 '''
        if self.db_type in dbcs:
            return dbcs[self.db_type](**self.config);
        
    def get(self, timeout=None):
        '''获取一个连接
        @param timeout:超时时间
        '''
        if timeout is None:
            timeout = self.maxWait
        conn = None
        if self.__freeConns.empty():#如果容器是空的,直接创建一个连接
            conn = self._create_conn()
        else:
            conn = self.__freeConns.get(timeout=timeout)
        conn.pool = self
        return conn
    
    def free(self, conn):
        '''将一个连接放回池中
        @param conn: 连接对象
        '''
        conn.pool = None
        if(self.__freeConns.full()):#如果当前连接池已满,直接关闭连接
            conn.release()
            return
        self.__freeConns.put_nowait(conn)
        
from abc import ABCMeta, abstractmethod

class PoolingConnection(object, metaclass=ABCMeta):
    def __init__(self, **config):
        self.conn = None
        self.config = config
        self.pool = None
        
    def __del__(self):
        self.release()
        
    def __enter__(self):
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        self.close()
        
    def release(self):
        print("release PoolingConnection..")
        if(self.conn is not None):
            self.conn.close()
            self.conn = None
        self.pool = None
            
    def close(self):
        if self.pool is None:
            raise PoolException("连接已关闭")
        self.pool.free(self)
        
    def __getattr__(self, val):
        if self.conn is None and self.pool is not None:
            self.conn = self._create_conn(**self.config)
        if self.conn is None:
            raise PoolException("无法创建数据库连接 或连接已关闭")
        return getattr(self.conn, val)

    @abstractmethod
    def _create_conn(self, **config):
        pass

class SQLit3PoolConnection(PoolingConnection):
    def _create_conn(self, **config):
        import sqlite3
        return sqlite3.connect(**config)

dbcs = {"SQLite3":SQLit3PoolConnection}

pool = Pool(database="F:\\test\\a")

def test():
    conn = pool.get()
    with conn:
        for a in conn.execute("SELECT * FROM A"):
            print(a)

if __name__ == "__main__":
    test()

  

以上代码在python3.0中测试通过……

分享到:
评论
5 楼 phyeas 2009-10-08  
谢谢LS提醒
4 楼 Maconel 2009-10-08  
弱引用可以解决这个问题。请搜索关键字"weakref".

例如:
import weakref

class A:
    def __init__(self):
        print 'A.__init__'
        self.b = None

    def __del__(self):
        print 'A.__del__'

class B:
    def __init__(self):
        print 'B.__init__'
        self.a = None

    def __del__(self):
        print 'B.__del__'

if __name__ == '__main__':
    a = A()
    b = B()
    a.b = weakref.proxy(b)
    b.a = a
3 楼 phyeas 2009-08-07  
呵呵,我主要看的是python3k的文档,python2.x的没怎么看
2 楼 iamsk 2009-08-06  
iamsk 写道
请问class PoolingConnection(object, metaclass=ABCMeta): 的意思是什么?
为何我的提示错误,execpt:)
改为class PoolingConnection(object):
或class PoolingConnection(ABCMeta):
都正常,第二句和你写的那个等价吗
初学django,多谢指导~ 

查了下,在python 2.x里
元类是在类里加 __metaclass__ = type
1 楼 iamsk 2009-08-06  
请问class PoolingConnection(object, metaclass=ABCMeta): 的意思是什么?
为何我的提示错误,execpt:)
改为class PoolingConnection(object):
或class PoolingConnection(ABCMeta):
都正常,第二句和你写的那个等价吗
初学django,多谢指导~ 

相关推荐

    学习目标:pythton基础-mysql数据库-python框架-简单Web-成功建站(含学习笔记).zip

    了解数据库连接池的概念也很重要,这对于在Python程序中高效地操作数据库至关重要。 Python框架部分,我们将重点关注Web开发中的Django和Flask两个主流框架。Django是一个功能强大的全栈框架,提供了模型-视图-控制...

    mysql-connector-python

    MySQL Connector/Python还支持连接池管理,这在处理大量并发连接时非常有用。你可以通过`ConnectionPool`类创建一个连接池,以便重复使用已建立的连接,从而提高性能。 此外,驱动程序还支持事务处理,这对于确保...

    python3.5全栈工程师零基础到项目实战全套

    - **连接MySQL数据库**:使用Python连接MySQL数据库的方法。 - **ORM框架**:通过ORM框架操作数据库,如SQLAlchemy。 ##### 13.Python3.5堡垒机学习 - **堡垒机原理**:介绍堡垒机的基本工作原理和应用场景。 - **...

    Python-一个从数据库取数据进行多线程爬文件存本地的爬虫

    6. **异常处理**:为了应对可能出现的错误,比如网络超时、数据库连接问题或文件写入错误,项目中应包含异常处理代码,使用`try/except`块来捕获并处理异常,保证程序的健壮性。 7. **日志记录**:在爬虫项目中,...

    Python-Pythonasyncio的一个快速PostgreSQL数据库客户端库

    1. **连接管理**:`asyncpg`支持创建连接池,方便管理和复用数据库连接。通过`create_pool`函数可以创建一个连接池,这样在并发环境下,多个任务可以共享连接,提高效率。 2. **异步查询**:使用`asyncpg`,你可以...

    python使用多线程查询数据库的实现示例

    1. **数据库连接池的运用及优势** - 数据库连接池是一种用于管理数据库连接的技术,它限制了数据库连接的最大个数,使得每次获取的连接都可以被重复利用。通过这种方式,可以显著减少建立和断开数据库连接的次数,...

    利用python list完成最简单的DB连接池方法

    在Python编程中,数据库连接池(Connection Pool)是一种管理数据库连接资源的技术,它可以有效地复用已存在的数据库连接,避免频繁创建和销毁连接带来的性能开销。本文将详细讲解如何使用Python列表来实现一个简单...

    Python库 | a_sync-0.2.0-py3-none-any.whl

    它可能包含了处理HTTP请求、数据库连接池管理、任务调度等多种后端开发常见需求的工具。 总的来说,"a_sync"库是Python异步编程领域的一个工具,它简化了编写非阻塞代码的过程,提升了程序的并发能力,尤其适合高...

    Python database.zip

    9. **连接池管理**: 当需要频繁创建和关闭数据库连接时,连接池(如psycopg2的连接池)可以有效管理数据库资源,提高性能。 10. **异步数据库操作**: 对于高并发的Web应用,Python有异步数据库库,如aiopg...

    深入Python3-带书签高清文字pdf版本

    9. **数据库编程**:介绍如何使用Python3与各种数据库(如MySQL、SQLite)进行交互,包括SQL语句的编写和数据库连接池的管理。 10. **单元测试和调试**:教授如何使用unittest模块进行代码测试,以及调试技巧,确保...

    Python库 | asyncmy-0.1.6.tar.gz

    1. **合理使用连接池**: 避免频繁创建和销毁连接,使用连接池来管理数据库连接。 2. **避免阻塞操作**: 在异步环境中,应尽量避免使用可能导致阻塞的同步函数,如长时间运行的计算任务。 3. **正确使用异常处理**:...

    Python库 | asyncpgx-1.1.5.tar.gz

    asyncpgx是一个基于Python的异步PostgreSQL数据库连接库,主要设计用于在asyncio环境中高效地操作数据库。这个库是asyncio和pgx(一个原生的PostgreSQL库)的结合,提供了简单、高性能的接口,使开发者能够在非阻塞...

    Python-aredis一个高效和用户友好的异步Redis客户端

    - **连接池管理**:自动维护连接池,优化资源使用,避免频繁建立和关闭连接的开销。 - **自动重连**:在连接断开时,`aredis` 可以自动尝试重新连接到 Redis 服务器。 - **批量操作**:支持批处理命令,提高执行效率...

    python如何通过twisted实现数据库异步插入

    在本例中,使用到了`adbapi`来创建数据库连接池,`pymysql`作为MySQL数据库的驱动。 2. 生成数据库连接池 使用`adbapi.ConnectionPool`方法创建数据库连接池。连接池的好处是可以复用数据库连接,减少每次连接...

    Python-试卷题目有答案-第13章-网络爬虫.docx

    2. **urllib3模块**:是urllib的增强版,提供更高级的功能,如连接池管理,处理重定向,支持HTTPS等。 3. **requests模块**:这是一个流行的第三方库,使用简单且功能强大,支持多种HTTP方法,自动处理Cookie、...

    最新Python课程体系.pdf

    - Python面向对象:类、对象、继承、多态。 - Python模块实战:导入和使用模块,自定义模块。 - 文件操作:读写文件,异常处理。 ### 2. Python网络爬虫基础及进阶实训(第2周-第4周) - **课程目标**:掌握...

    随书源代码.zip

    3. **第7章**:这通常是一个过渡章节,可能会讨论更高级的主题,如设计模式、异常处理、模块化编程,或者数据库连接池、线程同步等。 4. **第10章**:这个章节可能涉及到系统集成、API接口的使用、单元测试和调试...

    Windows系统下使用的pymssql python3.6

    对于频繁的数据库操作,可以使用连接池来管理数据库连接,提高效率: ```python from pymssql import connect from pymssql.pool import Pool pool = Pool(user='your_username', password='your_password', ....

    Python性能优化经验谈.zip

    - 使用数据库连接池:减少数据库连接的创建和销毁,提高整体性能。 9. **第三方库** - NumPy、Pandas和SciPy等库在数值计算和数据分析方面提供高性能支持。 - Cython、PyPy和Jython等解释器可以提升特定类型任务...

    Python-txRedis基于Twisted的Redis客户端

    5. **性能优化**:通过批处理和连接池技术,txRedis可以提高处理大量请求的效率。 四、使用txRedis 要开始使用txRedis,首先需要安装库,可以通过pip进行: ```bash pip install txredis ``` 然后在你的Twisted应用...

Global site tag (gtag.js) - Google Analytics