在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中測試通過……