python-mysql-连接池

利用内部队列

编写的简易的

支持上下文的

连接池,目前只支持多线程内的链接

代码如下

实现了 最大最小连接池的限制,链接回收,dml封装,动态维护链接等操作

import MySQLdb
import logging
import Queue
from threading import Thread
from contextlib import contextmanager
import time


class MysqlTool(object):
    """
    .. version 1.0
    :param is a dict has db connect parameter

    """

    def __new__(cls, parameter_dict, *args, **kwargs):
        dict_keys = ["host", "port", "user", "password", "db"]
        if isinstance(parameter_dict, dict):
            for keys in dict_keys:
                if keys not in parameter_dict:
                    raise KeyError("parameter do not have" + keys)
                return super(MysqlTool, cls).__new__(cls)
        raise TypeError("parameter is not a dict")

    def __init__(self, parameter_dict):
        self.host = parameter_dict['host']
        self.port = parameter_dict['port']
        self.user = parameter_dict['user']
        self.pwd = parameter_dict['password']
        self.db = parameter_dict['db']
        self.charset = parameter_dict.get('charset', 'utf8mb4')
        self.logger = logging.getLogger("baseClass.mysql")
        self.conn = None
        self.cu = None

    def getConnect(self, autocommit=True):
        try:
            self.conn = MySQLdb.Connect(host=self.host, port=self.port, user=self.user,
                                        passwd=self.pwd, db=self.db, charset=self.charset)
            self.conn.autocommit(autocommit)
        except Exception as e:
            self.conn = None
            self.logger.exception("GET MYSQL CONNECT ERROR")
            raise e

    def disConnect(self):
        if self.cu:
            self.cu.close()
        if self.conn:
            self.conn.close()

    def runSelect(self, sql, value_list=None, format_result=False):
        if self.conn:
            if format_result:
                self.cu = self.conn.cursor(MySQLdb.cursors.DictCursor)
            else:
                self.cu = self.conn.cursor()

            try:
                if value_list is None:
                    self.cu.execute(sql)
                else:
                    self.cu.execute(sql, value_list)

                return self.cu.fetchall()

            except Exception as e:
                self.logger.exception("SELECT DATA ERROR")
                raise e
        else:
            self.logger.error("No Mysql Connect")
            raise Exception("No Mysql Connect")

    def runInsertDeleteUpdate(self, sql, value_list=None, primary_key=None):
        if self.conn:
            self.cu = self.conn.cursor()
            try:
                if value_list is None:
                    execute_num = self.cu.execute(sql)
                else:
                    execute_num = self.cu.execute(sql, value_list)

                if primary_key:
                    return execute_num, self.cu.lastrowid
                else:
                    return execute_num

            except Exception as e:
                self.logger.exception("UPDATE OR DELETE ERROR")
                raise e
        else:
            self.logger.error("No Mysql Connect")
            raise Exception("No Mysql Connect")

    def __enter__(self):
        self.getConnect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.disConnect()
        if exc_type:
            logging.error("CLOSE CONNECT ERROR", exc_val)
        return True


class ConnectionsPool(Thread):
    """
    .. version 1.0
    :param parameter_dict is a connections parameter

    :param connect_class is a connections class

    :param max_size pool has max connections

    :param min_size pool has min connections
    """
    _class_queue = None
    _has_size = 0

    def __init__(self, parameter_dict, connect_class=MysqlTool, max_size=5, min_size=3):
        # TODO now only can use in MysqlTool
        super(ConnectionsPool, self).__init__()
        self.connect_class = connect_class
        self.parameter_dict = parameter_dict

        self._max_size = max_size
        self._min_size = min_size

        self._run_check = True
        self._error_check = True

    def __make_connections(self):
        self.__class__._class_queue = Queue.Queue(self._min_size + 1)
        for i in range(0, self._min_size):
            try:
                _temp_mysql_class = self.connect_class(self.parameter_dict)
            except TypeError as e:
                self._error_check = False
                raise e
            except AttributeError as e:
                self._error_check = False
                raise e
            _temp_mysql_class.getConnect()
            self.__class__._class_queue.put(_temp_mysql_class)
            self.__class__._has_size += 1

    def run(self):
        self.__make_connections()
        self.check_error()

        while self._run_check and self._error_check:
            time.sleep(1)
            _check_mysql_class = self.__class__._class_queue.get()
            if _check_mysql_class.conn.open:
                self.__class__._class_queue.put(_check_mysql_class)
                continue
            else:
                _queue_size = self.__class__._class_queue.qsize()
                if _queue_size > self._min_size:
                    self.__class__._has_size -= 1
                    continue
                _check_mysql_class = self.connect_class.getConnect(self.parameter_dict)
                self.__class__._class_queue.put(_check_mysql_class)

        while True and self._error_check:
            if self.__class__._has_size == 0:
                break
            if self.__class__._class_queue.qsize() > 0:
                _connect_class = self.__class__._class_queue.get()
                _connect_class.disConnect()
                self.__class__._has_size -= 1

    @contextmanager
    def connection_pool(self, timeout=3):
        self.check_error()
        try:
            connection = self.__class__._class_queue.get(timeout=timeout)
        except Queue.Empty:
            if self.__class__._has_size < self._max_size:
                connection = self.connect_class.getConnect(self.parameter_dict)
                self.__class__._has_size += 1
            else:
                try:
                    connection = self.__class__._class_queue.get(timeout=60)
                except Queue.Empty:
                    raise Exception("Beyond Max Connections")

        yield connection
        self.__class__._class_queue.put(connection)

    def set_runCheck(self, run_check):
        self._run_check = run_check

    def check_error(self):
        if False is self._error_check:
            raise Exception("Please Check logs, Connections has error")

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值