python Mysql数据库连接池组件封装(转载)
以前一直在用Java来开发,数据库连接池等都是有组件封装好的,直接使用即可,最近在尝试Python的学习,碰到了和数据库打交道的问题,和数据库打交道我们都知道,数据库连接池必不可少,不然要么就是程序异常不稳定,要么就是数据库莫名其妙挂了,
本篇博客主要是对数据库操作的简单封装,相当于一个DBHelper操作类
组件
Python中的数据库连接操作所需组件
pymysql:mysql的Python连接包
DBUtils:连接池组件
configparser:配置文件模块
mysql-connector-python:驱动包
以上模块都是必装组件,使用pip很轻松就安装
开始
组件的封装主要考虑到多种数据库、可配置的情况,因此我们的数据库相关信息不能使用硬编码的方式,需要将数据库放到配置文件中,这样和代码会有一个解耦,也不用频繁更改代码
代码
封装的类主要包含的基础方法:
提供查询的方法
分页查询的方法
插入数据
删除数据
更新数据
批量插入、删除、更新数据
配置文件
将数据库的相关信息写入db.conf配置文件中,配置文件如下:
- [master]
- # 数据库连接主机
- host=192.168.0.212
- # 数据库端口号
- port=
- # 用户名
- user=root
- # 密码
- password=
- # 数据库名称
- database=test
- # 数据库连接池最大连接数
- maxconnections=
- # 数据库连接池最小缓存数
- mincached=
- # 数据库连接池最大缓存数
- maxcached=
- [local111]
- # 数据库连接主机
- host=192.168.0.111
- # 数据库端口号
- port=
- # 用户名
- user=root
- # 密码
- password=
- # 数据库名称
- database=test
- # 数据库连接池最大连接数
- maxconnections=
- # 数据库连接池最小缓存数
- mincached=
- # 数据库连接池最大缓存数
- maxcached=
数据库的配置可以是多个,我们可以配置多个数据源,然后在代码中方便使用
MySQLConnection
数据库封装类MySQLConnection.py
,代码如下:
- #!/usr/bin/env python
- # -*- encoding: utf- -*-
- #!@File : database.py
- #!@Time : // :
- #!@Author : xiaoyumin
- #!@Version : 1.0
- #!@Contact : xiaoymin@foxmail.com
- #!@License : Copyright (C) Zhejiang xiaominfo Technology CO.,LTD.
- #!@Desc : 数据库连接池相关
- import pymysql
- from DBUtils.PooledDB import PooledDB
- import logging
- import configparser
- # 读取数据库配置信息
- config=configparser.ConfigParser()
- config.read('../db.conf',encoding='UTF-8')
- sections=config.sections()
- # 数据库工厂
- dbFactory={}
- for dbName in sections:
- # 读取相关属性
- maxconnections=config.get(dbName,"maxconnections")
- mincached=config.get(dbName,"mincached")
- maxcached=config.get(dbName,"maxcached")
- host=config.get(dbName,"host")
- port=config.get(dbName,"port")
- user=config.get(dbName,"user")
- password=config.get(dbName,"password")
- database=config.get(dbName,"database")
- databasePooled=PooledDB(creator=pymysql,
- maxconnections=int(maxconnections),
- mincached=int(mincached),
- maxcached=int(maxcached),
- blocking=True,
- cursorclass = pymysql.cursors.DictCursor,
- host=host,
- port=int(port),
- user=user,
- password=password,
- database=database)
- dbFactory[dbName]=databasePooled
- class MySQLConnection(object):
- """
- 数据库连接池代理对象
- 查询参数主要有两种类型
- 第一种:传入元祖类型,例如(,),这种方式主要是替代SQL语句中的%s展位符号
- 第二种: 传入字典类型,例如{"id":},此时我们的SQL语句需要使用键来代替展位符,例如:%(name)s
- """
- def __init__(self,dbName="master"):
- self.connect = dbFactory[dbName].connection()
- self.cursor = self.connect.cursor()
- logging.debug("获取数据库连接对象成功,连接池对象:{}".format(str(self.connect)))
- def execute(self,sql,param=None):
- """
- 基础更新、插入、删除操作
- :param sql:
- :param param:
- :return: 受影响的行数
- """
- ret=None
- try:
- if param==None:
- ret=self.cursor.execute(sql)
- else:
- ret=self.cursor.execute(sql,param)
- except TypeError as te:
- logging.debug("类型错误")
- logging.exception(te)
- return ret
- def query(self,sql,param=None):
- """
- 查询数据库
- :param sql: 查询SQL语句
- :param param: 参数
- :return: 返回集合
- """
- self.cursor.execute(sql,param)
- result=self.cursor.fetchall()
- return result
- def queryOne(self,sql,param=None):
- """
- 查询数据返回第一条
- :param sql: 查询SQL语句
- :param param: 参数
- :return: 返回第一条数据的字典
- """
- result=self.query(sql,param)
- if result:
- return result[]
- else:
- return None
- def listByPage(self,sql,current_page,page_size,param=None):
- """
- 分页查询当前表格数据
- :param sql: 查询SQL语句
- :param current_page: 当前页码
- :param page_size: 页码大小
- :param param:参数
- :return:
- """
- countSQL="select count(*) ct from ("+sql+") tmp "
- logging.debug("统计SQL:{}".format(sql))
- countNum=self.count(countSQL,param)
- offset=(current_page-)*page_size
- totalPage=int(countNum/page_size)
- if countNum % page_size>:
- totalPage = totalPage +
- pagination={"current_page":current_page,"page_size":page_size,"count":countNum,"total_page":totalPage}
- querySql="select * from ("+sql+") tmp limit %s,%s"
- logging.debug("查询SQL:{}".format(querySql))
- # 判断是否有参数
- if param==None:
- # 无参数
- pagination["data"]=self.query(querySql,(offset,page_size))
- else:
- # 有参数的情况,此时需要判断参数是元祖还是字典
- if isinstance(param,dict):
- # 字典的情况,因此需要添加字典
- querySql="select * from ("+sql+") tmp limit %(tmp_offset)s,%(tmp_pageSize)s"
- param["tmp_offset"]=offset
- param["tmp_pageSize"]=page_size
- pagination["data"]=self.query(querySql,param)
- elif isinstance(param,tuple):
- # 元祖的方式
- listtp=list(param)
- listtp.append(offset)
- listtp.append(page_size)
- pagination["data"]=self.query(querySql,tuple(listtp))
- else:
- # 基础类型
- listtp=[]
- listtp.append(param)
- listtp.append(offset)
- listtp.append(page_size)
- pagination["data"]=self.query(querySql,tuple(listtp))
- return pagination
- def count(self,sql,param=None):
- """
- 统计当前表记录行数
- :param sql: 统计SQL语句
- :param param: 参数
- :return: 当前记录行
- """
- ret=self.queryOne(sql,param)
- count=None
- if ret:
- for k,v in ret.items():
- count=v
- return count
- def insert(self,sql,param=None):
- """
- 数据库插入
- :param sql: SQL语句
- :param param: 参数
- :return: 受影响的行数
- """
- return self.execute(sql,param)
- def update(self,sql,param=None):
- """
- 更新操作
- :param sql: SQL语句
- :param param: 参数
- :return: 受影响的行数
- """
- return self.execute(sql,param)
- def delete(self,sql,param=None):
- """
- 删除操作
- :param sql: 删除SQL语句
- :param param: 参数
- :return: 受影响的行数
- """
- return self.execute(sql,param)
- def batch(self,sql,param=None):
- """
- 批量插入
- :param sql: 插入SQL语句
- :param param: 参数
- :return: 受影响的行数
- """
- return self.cursor.executemany(sql,param)
- def commit(self,param=None):
- """
- 提交数据库
- :param param:
- :return:
- """
- if param==None:
- self.connect.commit()
- else:
- self.connect.rollback()
- def close(self):
- """
- 关闭数据库连接
- :return:
- """
- if self.cursor:
- self.cursor.close()
- if self.connect:
- self.connect.close()
- logging.debug("释放数据库连接")
- return None
首先我们从配置文件中读取数据库的配置信息,放入dbFactory字典中,一个数据源key对应一个数据库连接池对象
使用
封装好我们的数据库组件后,接下来我们对于数据库的操作就很方便了
注意事项
我们在写SQL语句的时候需要注意我们的参数占位符的使用,注意有两种方式
%s:该方式你可以理解为任意字符,但是我们在参数传递的时候顺序必须正确,否则就会出现结果不一致的情况
%(fied)s:这种方式相对友好一些,我们传入的参数可以是字典对象,而不用关心我们的占位参数是否一致
获取不同的数据源连接
我们上面提到过,我们需要的是一个多数据源的情况,那么我们代码中应该如何使用呢?
- # 第一种方式,获取默认数据库的连接,在配置文件中配置名称为master的数据库
- connect=MySQLConnect()
- # 第二种方式,指定key名称获取数据库连接,如下:获取local111的数据库连接
- connect=MySQLConnect("local111")
新增数据
新增数据
- def insertByIndex():
- """
- 使用下标索引的方式插入数据
- """
- sql="insert into user(id,name) values(%s,%s)"
- # 获取数据库连接
- connect=MySQLConnection()
- try:
- # 执行插入动作
- connect.insert(sql,("","张三"))
- # 提交
- connect.commit()
- except Exception as e:
- logging.exception(e)
- finally:
- # 关闭数据库连接
- connect.close()
- def insertBatchByIndex():
- """
- 使用下标索引的方式批量插入数据
- """
- sql="insert into user(id,name) values(%s,%s)"
- # 获取数据库连接
- connect=MySQLConnection()
- try:
- # 执行批量插入动作
- data=[]
- # 放入的是元祖
- data.append(("","张三"))
- data.append(("","张三2"))
- connect.batch(sql,data)
- # 提交
- connect.commit()
- except Exception as e:
- logging.exception(e)
- finally:
- # 关闭数据库连接
- connect.close()
看了以上的方式或许你会觉得麻烦,为什么呢,因为我们在开发的时候一般都是使用字典居多,都是key-value的方式,因此使用索引的方式需要我们再申明一个有顺序的元祖对象,很麻烦
使用字典的方式如下:
- def insertByDict():
- """
- 使用下标索引的方式插入数据
- """
- sql="insert into user(id,name) values(%(id)s,%(name)s)"
- # 获取数据库连接
- connect=MySQLConnection()
- try:
- # 执行插入动作
- # 此时我们使用的是字典
- connect.insert(sql,{"name":"张三","id":""})
- # 提交,必须
- connect.commit()
- except Exception as e:
- logging.exception(e)
- finally:
- # 关闭数据库连接,必须
- connect.close()
- def insertBatchByDict():
- """
- 使用下标索引的方式批量插入数据
- """
- sql="insert into user(id,name) values(%(id)s,%(name)s)"
- # 获取数据库连接
- connect=MySQLConnection()
- try:
- # 执行批量插入动作
- data=[]
- # 放入的是自字典
- data.append({"name":"张三","id":""})
- data.append({"name":"张三1","id":""})
- connect.batch(sql,data)
- # 提交
- connect.commit()
- except Exception as e:
- logging.exception(e)
- finally:
- # 关闭数据库连接
- connect.close()
以上就是新增的方式,删除和修改同理也差不多.
分页查询数据
比如分页查询的示例:
- sql="select id,name,address from restaurant where province=%s "
- connect=MySQLConnection()
- try:
- page=
- size=
- pagination=connect.listByPage(sql,page,size,'浙江省')
- except Exception as e:
- logging.exception(e)
- finally:
- # 关闭数据库连接
- connect.close()
分页查询返回分页对象,是一个字典对象,主要包含属性:
current_page:当前页码
page_size:当前页码大小
count:当前统计SQL语句的表记录总数
total_page:当前总页码数
data:当前的数据集合,是一个字典集合对象
不分页的查询返回的是data集合字典对象,和分页使用方法类似
总结
以上就是一个简单的Python-MySQL数据库连接池组件,该组件同数据库交互过百万次,非常稳定,值得信赖~~!!!
附录
附上相关组件的说明文档:
https://cito.github.io/DBUtils/
https://pymysql.readthedocs.io/en/latest/modules/cursors.html
转载地址:https://blog.csdn.net/u010192145/article/details/102487255
python Mysql数据库连接池组件封装(转载)的更多相关文章
- DbUtil组件及C3P0数据库连接池组件的使用
DbUtils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能. 使用c ...
- Python MySQL 数据库连接不同方式
PyMySQL 驱动连接 什么是 PyMySQL?PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb. PyMySQL 遵循 P ...
- Python - MySQL 数据库连接 - PyMySQL 驱动 - 第二十五天
序言 本文我们为大家介绍 Python3 使用 PyMySQL 连接数据库,并实现简单的增删改查. 什么是 PyMySQL? PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务 ...
- Python MySQL数据库连接模块
1. MySQLdb只支持在Python 2版本使用MySQLdb是用于Python链接Mysql数据库的接口.a.pip安装 直接使用pip进行安装,在此之前需要安装一些系统依赖包. ● CentO ...
- Python实现Mysql数据库连接池
python连接Mysql数据库: python编程中可以使用MySQLdb进行数据库的连接及诸如查询/插入/更新等操作,但是每次连接mysql数据库请求时,都是独立的去请求访问,相当浪费资源,而且访 ...
- python mysql redis mongodb selneium requests二次封装为什么大都是使用类的原因,一点见解
1.python mysql redis mongodb selneium requests举得这5个库里面的主要被用户使用的东西全都是面向对象的,包括requests.get函数是里面每次都是实例 ...
- [转载]linux+nginx+python+mysql安装文档
原文地址:linux+nginx+python+mysql安装文档作者:oracletom # 开发包(如果centos没有安装数据库服务,那么要安装下面的mysql开发包) MySQL-devel- ...
- 10分钟教你Python+MySQL数据库操作
欲直接下载代码文件,关注我们的公众号哦!查看历史消息即可! 本文介绍如何利用python来对MySQL数据库进行操作,本文将主要从以下几个方面展开介绍: 1.数据库介绍 2.MySQL数据库安装和设置 ...
- mysql数据库连接池使用(三)数据库元数据信息反射数据库获取数据库信息
1.1. mysql数据库连接池使用(三)数据库元数据信息反射数据库获取数据库信息 有时候我们想要获取到数据库的基本信息,当前程序连接的那个数据库,数据库的版本信息,数据库中有哪些表,表中都有什么字段 ...
随机推荐
- 七、Vue组件库:Element、Swiper(轮播专用组件)
一.vue的Element组件库 官网:https://element.eleme.cn/#/zh-CN 1.1安装 推荐安装方法: 首先要进入项目目录 cnpm i element-ui -S 或 ...
- msf自动连接postgresql配置
今天做了一下msf连接数据库的配置,中间碰到了一些坑点这里就不详细叙述了,开始正确的操作方式. 首先对postgresql进行配置以方便连接. root@kali:~# service postgre ...
- POJ 2309:BST lowbit
BST Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9140 Accepted: 5580 Description C ...
- 活动目录对象属性批量修改工具------ADModify
最近下载了一个可以修改活动目录用户.组.联系人等活动目录对象属性的工具,试用了一下,发现还是蛮好用的,并且还可以修改对象的扩展属性,如:在活动目录中安装了Exchange 2003,Exchange ...
- Rabbitmq之高级特性——实现消费端限流&NACK重回队列
如果是高并发下,rabbitmq服务器上收到成千上万条消息,那么当打开消费端时,这些消息必定喷涌而来,导致消费端消费不过来甚至挂掉都有可能. 在非自动确认的模式下,可以采用限流模式,rabbitmq ...
- 2 —— js语法 —— 对象和方法的声明 。变量提升。闭包
一,声明对象 var obj1 = {}; var obj2 = {name:'kk',age:18,fun:function{ // name,age,fun为对象的属性,只是属性 ...
- java核心-多线程-零碎知识收集
1.不能使用Integer作为并发锁 原因:synchronized(Integer)时,当值发生改变时,基本上每次锁住的都是不同的对象实例,想要保证线程安全,推荐使用AtomicInteger之类会 ...
- 069-PHP数组下标
<?php $arr=array(98,'hello',67,'A',85,NULL); //定义一个数组 $x=0; //定义三个作为下标的变量 $y=3; $z=5; echo " ...
- HDU 4866 多校1 主席树+扫描线
终于是解决了这个题目了 不过不知道下一次碰到主席树到底做不做的出来,这个东西稍微难一点就不一定能做得出 离散化+扫描线式的建树,所以对于某个坐标二分找到对应的那颗主席树,即搜索出结果即可(因为是扫描线 ...
- springboot启动项目报错:ERROR:o.s.b.d.LoggingFailureAnalysisReporter解决办法
原因是引入了spring security的依赖,将spring security对应的依赖删除即可. 具体可参照: https://blog.csdn.net/qq_37887131/article ...