Python学习笔记(二十四)基于DBUtils构建数据库连接池

参考资料:

https://blog.csdn.net/zbc1090549839/article/details/51336458
http://blog.sina.com.cn/s/blog_6f688450010148d2.html
1、 概述。
      对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
      解决上述问题的直接思路就是:连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。
      数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。如:外部使用者可通过getConnection 方法获取连接,使用完毕后再通过releaseConnection 方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
数据库连接池技术带来的优势:
      (1)资源重用
      由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
      (2)更快的系统响应速度
      数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
      (3)新的资源分配手段
      对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术。
      (4) 统一的连接管理,避免数据库连接泄漏
      在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。
2、 DBUtils
      DBUtils是一套Python数据库连接池包,并允许对非线程安全的数据库接口进行线程安全包装。DBUtils提供两种外部接口:
      (1)PersistentDB :提供线程专用的数据库连接,并自动管理连接。
      (2)PooledDB :提供线程间可共享的数据库连接,并自动管理连接。
      DBUtils的安装方式也很简单,可直接使用Pip命令在线安装或从参考资料3给定的网站下载安装包安装。
3、利用DBUtils建立数据库连接池工具包。
      下面以MySQL为例,学习利用DBUtils建立数据库连接池工具包。
      在编码之前需要从https://pypi.python.org/pypi/MySQL-python/1.2.5下载安装MySQLDb。
      如果是64位操作系统,请从http://www.lfd.uci.edu/~gohlke/pythonlibs/下载安装其64位版本。
      下面是我的学习代码:
from DBUtils.PooledDB import PooledDB
from MySQLdb.cursors import DictCursor
import MySQLdb

class MySQLManager(object):
    #申明1个连接池对象
    __pool = None
    #错误信息
    error = None
    errorcode = 0

    def __init__(self):
        self.conn = MySQLManager.__getconn()
        if self.conn:
            self.cursor = self.conn.cursor()

    @staticmethod
    def __getconn():
        '''
        @summary 静态方法,从连接池取出连接
        @return connection
        '''
        try:
            if MySQLManager.__pool == None:
                MySQLManager.__pool = PooledDB(MySQLdb, mincached = 1, maxcached = 20,  
                                  host = '::1', port = 3306, user = 'root', 
                                  passwd = 'alvin', db = 'test', use_unicode = True, cursorclass=DictCursor)
        except BaseException, e:
            MySQLManager.errorcode = 1
            MySQLManager.error = e.message
        return MySQLManager.__pool.connection() if MySQLManager.__pool else None

    def begin(self):  
        """ 
        @summary: 开启事务 
        """  
        self.conn.autocommit(0)  
   
    def end(self, option = 'commit'):  
        """ 
        @summary: 结束事务 
        """  
        if option == 'commit':  
            self.conn.commit()  
        else:  
            self.conn.rollback() 

    def dispose(self, isEnd = 1):  
        """ 
        @summary: 释放连接池资源
        @isEnd: 1-正常提交 2-回滚 
        """  
        if isEnd == 1:  
            self.end('commit')  
        else:  
            self.end('rollback');  
        self.cursor.close()  
        self.conn.close()

    #执行查询语句
    def executeSQL(self, sql):
        self.errorcode = 0
        if self.cursor:
            try:
                self.cursor.execute(sql)
            except BaseException, e:
                self.errorcode = 5
                self.error = e.message
        else:
            self.errorcode = 1

    #查询并获取结果
    def getValues(self, sql):
        self.errorcode = 0
        values = None
        if self.cursor:
            try:
                cursor.execute(sql)
                values = cursor.fetchall()
            except BaseException, e:
                self.errorcode = 4
                self.error = e.message
        else:
            self.errorcode = 1
        return values

    #创建表
    def createTable(self, tablename, fields):
        self.errorcode = 0
        if self.cursor:
            try:
                sFields = ''
                for s in fields:
                    if sFields != '':
                        sFields = sFields + ','
                    sFields = sFields + s
                sql = 'CREATE TABLE %s(%s)' % (tablename, sFields)
                cursor.execute(sql)
            except BaseException, e:
                self.errorcode = 3
                self.error = e.message
        else:
            self.errorcode = 1

def Test():
    #连接数据库
    db = MySQLManager()
    if not db.conn or not db.cursor:
        print 'connect failure %d:%s' % (db.errorcode, db.error)
        return
    #输入表名
    t = raw_input('input a tablename:')
    #输入字段定义
    fields = []
    while True:
        f = raw_input('input field define, none to break:')
        if f and f != '':
            fields.append(f)
        else:
            break
    #创建表
    db.createTable(t, fields)
    if db.errorcode == 0:
        print 'create successfull!'
    else:
        print 'create failure, error: %d, %s' % (db.errorcode, db.error)   
    #执行SQL语句
    sql = raw_input('input a sql to execute:')
    db.executeSQL(sql)
    if db.errorcode != 0:
        print 'error on execute SQL %s: %d %s' % (sql, db.errorcode, db.error)
    else:
        print 'execute successful!'
    #查询
    values = db.getValues('SELECT * FROM %s' % t)
    if db.errorcode == 0:
        print values
    else:
        print 'error on query table %s:%d %s' % (t, db.errorcode, db.error)
    #关闭数据库连接
    db.dispose()

注:PooledDB参数说明:
dbapi :数据库接口
mincached :启动时开启的空连接数量
maxcached :连接池最大可用连接数量
maxshared :连接池最大可共享连接数量
maxconnections :最大允许连接数量
blocking :达到最大数量时是否阻塞
maxusage :单个连接最大复用次数

另外,在学习过程中用到了MySQL的几个命令:

(1)查询连接端口配置:show global variables like 'port'

(2)查询可连接的主机及用户名:select host, user from mysql.user
今天就学习到这里,下一节学习Python的第三方ORM框架。

猜你喜欢

转载自blog.csdn.net/alvin_2005/article/details/80646944