數據庫、redis連接池

import contextlib
import redis
import pymysql

IS_DEV = False
if IS_DEV:
    # 正式版redis
    REDIS = {
        'host': '**********.redis.rds.aliyuncs.com',
        'port': 6379,
        'db': 11,
        'password': '********'
    }
    # 正式版數據庫
    DB_INFO = {
        'host': '************.mysql.rds.aliyuncs.com',
        'port': 3306,
        'user': 'mysqlsa',
        'password': '********',
        'db': '*****agent'
    }
    ADS_INFO = {
        'host': '************.ads.aliyuncs.com',
        'port': 3306,
        'user': 'agent_sa',
        'password': '********',
        'db': '*****agent'
    }
else:
    # 測試版 線下 redis
    REDIS = {
        'host': '192.168.0.8',
        'port': 6379,
        'db': 10,
        'password': '******'
    }
    # 測試版數據庫
    DB_INFO = {
        'host': '***********.mysql.rds.aliyuncs.com',
        'port': 3306,
        'user': 'mysqlsa',
        'password': '*******',
        'db': '******agent'
    }
    ADS_INFO = {
        'host': '***********.ads.aliyuncs.com',
        'port': 3306,
        'user': 'mysqlsa',
        'password': '********',
        'db': '******agent'
    }


# 創建數據庫連接池池
class DatabaseConnectPool:
    '''
    數據庫連接池類  支持多庫多池
    '''

    def __init__(self, module, credentials, size=10):
        '''
        :param module: 數據庫驅動 例如 pymysql
        :param credentials: 數據庫連接信息
        credentials={
                'DB_INFO' = {
                'host': 'rm-uf6t4r3u8vea8u340971.mysql.rds.aliyuncs.com',
                'port': 3306,
                'user': 'res_sql',
                'password': 'Lansi321',
                'db': 'lansi_agent'
            }
        }
        :param size: 每個連接池最大連接數量
        '''
        self.__module = module
        self.__credentials = credentials
        self.__databases = {}
        self.__size = size

    def get(self, pool_name):
        '''
        根據連接池名稱獲取連接
        :param pool_name:
        :return:
        '''
        if pool_name not in self.__credentials:
            raise Exception('數據庫信息不存在')
        elif pool_name not in self.__databases:
            self.__databases[pool_name] = []
            self.create_connection(pool_name)
        elif not self.__databases[pool_name]:
            self.create_connection(pool_name)
        con = self.__databases[pool_name].pop()
        try:
            con.ping()
        except Exception as e:
            con = e
        return con

    def create_connection(self, pool_name):
        '''
        創建數據庫連接
        :param pool_name:
        :return:
        '''
        if pool_name not in self.__credentials:
            raise Exception('數據庫信息不存在')
        db_info = self.__credentials[pool_name]
        con = self.__module.connect(**db_info)
        self.__databases[pool_name].append(con)

    def put(self, pool_name, con):
        '''
        把數據庫連接放回連接池
        :param pool_name:
        :param con:
        :return:
        '''
        if isinstance(con, self.__module.connections.Connection):
            if len(self.__databases[pool_name]) > self.__size:
                con.close()
            self.__databases[pool_name].insert(0, con)
        else:
            try:
                con.close()
            except:
                pass

    def __del__(self):
        for con_list in self.__databases.values():
            for con in con_list:
                try:
                    con.close()
                except:
                    pass


db_info = {
    # 連接池名稱: 數據庫信息
    'rds': DB_INFO,
    'ads': ADS_INFO
}
db_pool = DatabaseConnectPool(pymysql, db_info)


def search_sql_pool(total_sql, pool_name='rds', result_type='dict'):
    '''
    多庫查詢
    :param total_sql: 被執行的sql
    :param pool_name: 連接池名稱
    :param db_name: 數據庫名
    :param result_type: 返回結果類型  默認字典
    :return:
    '''
    # 從數據庫連接池池中獲取連接池
    db = db_pool.get(pool_name)
    # 如果沒有取出連接  直到取到連接
    while isinstance(db, str):
        db = db_pool.get(pool_name)
    if result_type == 'dict':
        try:
            with db.cursor(pymysql.cursors.DictCursor) as cursor:
                # 使⽤execute⽅法執⾏SQL語句
                cursor.execute(total_sql)
                # 獲取數據
                data = cursor.fetchall()
            # 提交
            db.commit()
        except Exception as e:
            data = e
        finally:
            db_pool.put(pool_name, db)
    # 返回列表類型查詢結果
    else:
        try:
            with db.cursor() as cursor:
                # 使⽤execute⽅法執⾏SQL語句
                cursor.execute(total_sql)
                # 獲取數據
                data = cursor.fetchall()
            # 提交
            db.commit()
        except Exception as e:
            data = e
        finally:
            db_pool.put(pool_name, db)
    return data


def rds_sql(total_sql):
    '''
    RDS查詢  返回字典
    :param total_sql:
    :return:
    '''
    return search_sql_pool(total_sql, pool_name='rds')


def rds_list_sql(total_sql):
    '''
    RDS查詢  返回列表
    :param total_sql:
    :return:
    '''
    return search_sql_pool(total_sql, pool_name='rds', result_type='list')


def ads_sql(total_sql):
    '''
    ADS查詢  返回字典
    :param total_sql:
    :return:
    '''
    return search_sql_pool(total_sql, pool_name='ads')


def ads_list_sql(total_sql):
    '''
    ADS查詢  返回列表
    :param total_sql:
    :return:
    '''
    return search_sql_pool(total_sql, pool_name='ads', result_type='list')


# 創建redis連接池
class RedisConnectPool:
    '''
    redis連接池 使用的是對redis模塊封裝了一層
    '''

    def __init__(self, redis_info, size=10):
        '''
        初始化連接池
        :param redis_info: {
            'host': '192.168.0.8',
            'port': 6379,
            'db': 10,
            'password': 'Lansi.123'
        }
        :param size: 每個連接池最大連接數量
        '''
        self.__redis_info = redis_info
        self.__connections = []
        self.__size = size

    @contextlib.contextmanager
    def get(self):
        '''
        獲取一個連接
        :return:
        '''
        if not self.__connections:
            self.create_connection()
        con = self.__connections.pop()
        con.ping()
        yield con
        self.put(con)

    def create_connection(self):
        '''
        創建連接
        :return:
        '''
        con = redis.Redis(decode_responses=True, **self.__redis_info)
        self.__connections.append(con)

    def put(self, con):
        '''
        把連接放回連接池
        :param con:
        :return:
        '''
        if isinstance(con, str):
            return
        if self.__size < len(self.__connections):
            con.close()
        elif isinstance(con, redis.client.Redis):
            self.__connections.insert(0, con)
        else:
            try:
                con.close()
            except:
                pass

    def __del__(self):
        for con in self.__connections:
            try:
                con.close()
            except:
                pass


redis_pool = RedisConnectPool(REDIS)

if __name__ == '__main__':
    date = rds_sql('select now()')
    if isinstance(date, str):
        print('ERROR: {}'.format(date))
    else:
        print(date)

    with redis_pool.get() as con:
        print(con.keys('*'))
        print(con.get('test_key'))

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章