Python封裝pymongo模組自動關閉串連

來源:互聯網
上載者:User

在我工作的項目裡面使用了mongodb.自然也用到了pymongo.但是它都是在大片的函數裡面使用類似於這樣的方式

 代碼如下 複製代碼
import db
def test():
    ...
    db.test.find_one()
    ...



但是問題是在使用完都沒有關閉串連,這樣多台伺服器串連我這台mongodb伺服器,在業務高峰期就會佔滿我的串連, 我當時總結造成這個原因的問題有以下三種:

    上面說的用完db不關閉串連而是等著db逾時

    注意上面的import,其實在import檔案的時候資料庫連接就已經產生了,沒有在需要的時候才建立, 佔滿我連線應用程式其實有很多沒有用,浪費了

    nginx、uwsgi,celery等應用配置的問題,造成過多的執行個體,其實根本無益

我今天寫的一個封裝pymongo和關閉資料庫連接的裝飾器

 代碼如下 複製代碼
#/usr/bin/env python
# coding=utf-8

"""
1. 封裝資料庫操作(INSERT,FIND,UPDATE)
2. 函數執行完MONGODB操作後關閉資料庫連接
"""

from functools import wraps
from pymongo.database import Database

try:
    from pymongo import MongoClient
except ImportError:
    # 好像2.4之前的pymongo都沒有MongoClient,現在官網已經把Connection拋棄了
    import warnings
    warnings.warn("Strongly recommend upgrading to the latest version pymongo version,"
                  "Connection is DEPRECATED: Please use mongo_client instead.")
    from pymongo import Connection as MongoClient


class Mongo(object):

    '''封裝資料庫操作'''

    def __init__(self, host='localhost', port=27017, database='test',
                 max_pool_size=10, timeout=10):
        self.host = host
        self.port = port
        self.max_pool_size = max_pool_size
        self.timeout = timeout
        self.database = database

    @property
    def connect(self):
        # 我這裡是為了使用類似"db.集合.操作"的操作的時候才會產生資料庫連接,其實pymongo已經實現了進程池,也可以把這個db放在__init__裡面,
        # 比如我把db關掉有其他的資料庫調用串連又會產生,並且不影響使用.我這裡只是想每次執行資料庫產生一個串連用完關掉-自己控制自己的
        return MongoClientself.host, self.port, max_pool_size=self.max_pool_size,
                  connectTimeoutMS=60 * 60 * self.timeout)

    def __getitem__(self, collection):
        # 為了相容db[集合].操作的用法
        return self.__getattr__(collection)

    def __getattr__(self, collection_or_func):
        db = self.connect[self.database]
        if collection_or_func in Database.__dict__:
            # 當調用的是db的方法就直接返回
            return getattr(db, collection_or_func)
        # 否則委派給Collection
        return Collection(db, collection_or_func)


class Collection(object):

    def __init__(self, db, collection):
        self.collection = getattr(db, collection)

    def __getattr__(self, operation):
        # 我這個封裝只是為了攔截一部分操作,不符合的就直接raise屬性錯誤
        control_type = ['disconnect', 'insert', 'update', 'find', 'find_one']
        if operation in control_type:
            return getattr(self.collection, operation)
        raise AttributeError(operation)


def close_db(dbs=['db']):
    '''
    關閉mongodb資料庫連接
    db : 在執行函數裡面使用的db的名字(大部分是db,也會有s_db)
        Usage::
            >>>s_db = Mongo()
            >>>@close_db(['s_db'])
            ...: def test():
            ...:     print s_db.test.insert({'a': 1, 'b': 2})
            ...:
    '''
    def _deco(func):
        @wraps(func)
        def _call(*args, **kwargs):
            result = func(*args, **kwargs)
            for db in dbs:
                try:
                    func.func_globals[db].connection.disconnect()
                except KeyError:
                    pass
            return result
        return _call
    return _deco



PS: 在我測試的時候發現,使用Mongo()類產生的db,操作完會自動關閉串連了…
怎麼樣給一個很大的檔案每個函數都加上面的這個裝飾器?

項目每個指令碼的代碼都很長,函數也很多,並且每個函數裡面使用的db的名字都不同,比如有一些一些風格:

 代碼如下 複製代碼
db.test.find_one()
s_db.test.insert(dict(test='test'))
...



每個函數加一個裝飾器,好費勁,就想能不能自動分辨檔案中的函數然後給他們自動加裝飾器,然後就有以下的一個做好的指令碼:

 代碼如下 複製代碼
#coding=utf-8

from functools import wraps
import copy
import types

def wrap(func):
    @wraps(func)
    def _call(*args, **kwargs):
        result = func(*args, **kwargs)
        print 'wrap you'
        return result
    return _call

def test():
    print 'test'

def test2():
    print 'test3'

glocal_dict = copy.copy(globals())

func_list = [[k, v] for k, v in glocal_dict.iteritems() if not k.startswith('__')]

for func_name, func in func_list:
    if  func_name in ['wraps', 'copy', 'wrap', 'types']:
        continue
    if types.FunctionType  == type(func):
        globals()[func_name]= wrap(func)



這樣當你調用的時候自動就有了裝飾器:

 代碼如下 複製代碼
>>> from test import test
>>> test()
test
wrap you
>>>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.