python单例模式----实现数据库连接池
单例模式介绍
适用场景:
单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。还有windows系统的回收站和任务管理器,只能打开一个。
2.控制资源的情况下,方便资源之间的互相通信。多线程的线程池的设计一般就是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
实现单例模式的几种方法
1. 使用模块
其实,python的模块就是天然的单例模式,因为模块在第一次导入的时候,会生成.pyc文件,当第二次导入的时候,就会直接加载.pyc文件,而不是再次执行模块代码.如果我们把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了,再在另一个文件导入这个类实例.
# mysingleton.py
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
# work.py
from mysingleton import singleton
2. 使用装饰器
装饰器里面的外层变量定义一个字典,里面存放这个类的实例.当第一次创建的时候,就将这个实例保存到这个字典中.然后以后每次创建对象的时候,都去这个字典中判断一下,如果已经被实例化,就直接取这个实例对象.如果不存在就保存到字典中.
def singleton(cls):
# 创建一个字典用来保存类的实例对象
_instance = {}
def _singleton(*args, **kwargs):
# 先判断这个类有没有对象
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs) # 创建一个对象,并保存到字典当中
# 将实例对象返回
return _instance[cls]
return _singleton
@singleton
class A(object):
def __init__(self, x=0):
self.x = x
print('这是A的类的初始化方法')
a1 = A(2)
a2 = A(3)
print(id(a1) == id(a2))
3. 基于new方法
一个对象的实例化过程是先执行类的new方法,如果我们没有写,默认会调用object的new方法,返回一个实例化对象,然后再调用init方法,对这个对象进行初始化,我们可以根据这个实现单例
class Singleton(object):
def __init__(self, *args, **kwargs):
pass
#在类的__new__方法中先判断是不是存在实例,如果存在实例,就直接返回,如果不存在实例就创建
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
Singleton._instance = super().__new__(cls)
return Singleton._instance
a1 = Singleton()
a2 = Singleton()
print(id(a1) == id(a2))
数据库连接池
数据库连接池的设计一般是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的。使用单例模式来维护连接池,就可以大大降低这种损耗,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
def connection_pool(n):
assert n < 20 # 限制连接池实例数量
def singleton(cls):
# 创建一个列表用来保存类的实例对象
_instance_list = list()
def _singleton(*args, **kwargs):
# 先判断这个实例列表有没有实例,即是不是类第一次init
while len(_instance_list) < n:
_instance_list.append(cls(*args, **kwargs))
# 循环返回实例
_instance_list.insert(0,_instance_list[-1])
return _instance_list.pop()
return _singleton
return singleton
import pymongo
MONGODB_URL = ""
MONGODB_DATABASE = ""
@connection_pool(3) # 将三个连接实例加入连接池中
class MongodbModule(object):
def __init__(self,url = MONGODB_URL,db = MONGODB_DATABASE):
self.myclient = pymongo.MongoClient(url)
self.mydb = self.myclient[db]
# 循环返回mongodb的实例
mongo = MongodbModule()