以前一直在用Java来开发,数据库连接池等都是有组件封装好的,直接使用即可,最近在尝试Python的学习,碰到了和数据库打交道的问题,和数据库打交道我们都知道,数据库连接池必不可少,不然要么就是程序异常不稳定,要么就是数据库莫名其妙挂了,

本篇博客主要是对数据库操作的简单封装,相当于一个DBHelper操作类

组件
Python中的数据库连接操作所需组件

pymysql:mysql的Python连接包
DBUtils:连接池组件
configparser:配置文件模块
mysql-connector-python:驱动包
以上模块都是必装组件,使用pip很轻松就安装

开始
组件的封装主要考虑到多种数据库、可配置的情况,因此我们的数据库相关信息不能使用硬编码的方式,需要将数据库放到配置文件中,这样和代码会有一个解耦,也不用频繁更改代码

代码
封装的类主要包含的基础方法:

提供查询的方法
分页查询的方法
插入数据
删除数据
更新数据
批量插入、删除、更新数据
配置文件
将数据库的相关信息写入db.conf配置文件中,配置文件如下:

  1. [master]
  2. # 数据库连接主机
  3. host=192.168.0.212
  4. # 数据库端口号
  5. port=
  6. # 用户名
  7. user=root
  8. # 密码
  9. password=
  10. # 数据库名称
  11. database=test
  12. # 数据库连接池最大连接数
  13. maxconnections=
  14. # 数据库连接池最小缓存数
  15. mincached=
  16. # 数据库连接池最大缓存数
  17. maxcached=
  18.  
  19. [local111]
  20. # 数据库连接主机
  21. host=192.168.0.111
  22. # 数据库端口号
  23. port=
  24. # 用户名
  25. user=root
  26. # 密码
  27. password=
  28. # 数据库名称
  29. database=test
  30. # 数据库连接池最大连接数
  31. maxconnections=
  32. # 数据库连接池最小缓存数
  33. mincached=
  34. # 数据库连接池最大缓存数
  35. maxcached=

数据库的配置可以是多个,我们可以配置多个数据源,然后在代码中方便使用

MySQLConnection

数据库封装类MySQLConnection.py,代码如下:

  1. #!/usr/bin/env python
  2. # -*- encoding: utf- -*-
  3. #!@File : database.py
  4. #!@Time : // :
  5. #!@Author : xiaoyumin
  6. #!@Version : 1.0
  7. #!@Contact : xiaoymin@foxmail.com
  8. #!@License : Copyright (C) Zhejiang xiaominfo Technology CO.,LTD.
  9. #!@Desc : 数据库连接池相关
  10. import pymysql
  11. from DBUtils.PooledDB import PooledDB
  12. import logging
  13. import configparser
  14.  
  15. # 读取数据库配置信息
  16. config=configparser.ConfigParser()
  17. config.read('../db.conf',encoding='UTF-8')
  18. sections=config.sections()
  19. # 数据库工厂
  20. dbFactory={}
  21. for dbName in sections:
  22. # 读取相关属性
  23. maxconnections=config.get(dbName,"maxconnections")
  24. mincached=config.get(dbName,"mincached")
  25. maxcached=config.get(dbName,"maxcached")
  26. host=config.get(dbName,"host")
  27. port=config.get(dbName,"port")
  28. user=config.get(dbName,"user")
  29. password=config.get(dbName,"password")
  30. database=config.get(dbName,"database")
  31. databasePooled=PooledDB(creator=pymysql,
  32. maxconnections=int(maxconnections),
  33. mincached=int(mincached),
  34. maxcached=int(maxcached),
  35. blocking=True,
  36. cursorclass = pymysql.cursors.DictCursor,
  37. host=host,
  38. port=int(port),
  39. user=user,
  40. password=password,
  41. database=database)
  42. dbFactory[dbName]=databasePooled
  43.  
  44. class MySQLConnection(object):
  45. """
  46. 数据库连接池代理对象
  47. 查询参数主要有两种类型
  48. 第一种:传入元祖类型,例如(,),这种方式主要是替代SQL语句中的%s展位符号
  49. 第二种: 传入字典类型,例如{"id":},此时我们的SQL语句需要使用键来代替展位符,例如:%(name)s
  50. """
  51. def __init__(self,dbName="master"):
  52. self.connect = dbFactory[dbName].connection()
  53. self.cursor = self.connect.cursor()
  54. logging.debug("获取数据库连接对象成功,连接池对象:{}".format(str(self.connect)))
  55.  
  56. def execute(self,sql,param=None):
  57. """
  58. 基础更新、插入、删除操作
  59. :param sql:
  60. :param param:
  61. :return: 受影响的行数
  62. """
  63. ret=None
  64. try:
  65. if param==None:
  66. ret=self.cursor.execute(sql)
  67. else:
  68. ret=self.cursor.execute(sql,param)
  69. except TypeError as te:
  70. logging.debug("类型错误")
  71. logging.exception(te)
  72. return ret
  73. def query(self,sql,param=None):
  74. """
  75. 查询数据库
  76. :param sql: 查询SQL语句
  77. :param param: 参数
  78. :return: 返回集合
  79. """
  80. self.cursor.execute(sql,param)
  81. result=self.cursor.fetchall()
  82. return result
  83. def queryOne(self,sql,param=None):
  84. """
  85. 查询数据返回第一条
  86. :param sql: 查询SQL语句
  87. :param param: 参数
  88. :return: 返回第一条数据的字典
  89. """
  90. result=self.query(sql,param)
  91. if result:
  92. return result[]
  93. else:
  94. return None
  95. def listByPage(self,sql,current_page,page_size,param=None):
  96. """
  97. 分页查询当前表格数据
  98. :param sql: 查询SQL语句
  99. :param current_page: 当前页码
  100. :param page_size: 页码大小
  101. :param param:参数
  102. :return:
  103. """
  104. countSQL="select count(*) ct from ("+sql+") tmp "
  105. logging.debug("统计SQL:{}".format(sql))
  106. countNum=self.count(countSQL,param)
  107. offset=(current_page-)*page_size
  108. totalPage=int(countNum/page_size)
  109. if countNum % page_size>:
  110. totalPage = totalPage +
  111. pagination={"current_page":current_page,"page_size":page_size,"count":countNum,"total_page":totalPage}
  112. querySql="select * from ("+sql+") tmp limit %s,%s"
  113. logging.debug("查询SQL:{}".format(querySql))
  114. # 判断是否有参数
  115. if param==None:
  116. # 无参数
  117. pagination["data"]=self.query(querySql,(offset,page_size))
  118. else:
  119. # 有参数的情况,此时需要判断参数是元祖还是字典
  120. if isinstance(param,dict):
  121. # 字典的情况,因此需要添加字典
  122. querySql="select * from ("+sql+") tmp limit %(tmp_offset)s,%(tmp_pageSize)s"
  123. param["tmp_offset"]=offset
  124. param["tmp_pageSize"]=page_size
  125. pagination["data"]=self.query(querySql,param)
  126. elif isinstance(param,tuple):
  127. # 元祖的方式
  128. listtp=list(param)
  129. listtp.append(offset)
  130. listtp.append(page_size)
  131. pagination["data"]=self.query(querySql,tuple(listtp))
  132. else:
  133. # 基础类型
  134. listtp=[]
  135. listtp.append(param)
  136. listtp.append(offset)
  137. listtp.append(page_size)
  138. pagination["data"]=self.query(querySql,tuple(listtp))
  139. return pagination
  140. def count(self,sql,param=None):
  141. """
  142. 统计当前表记录行数
  143. :param sql: 统计SQL语句
  144. :param param: 参数
  145. :return: 当前记录行
  146. """
  147. ret=self.queryOne(sql,param)
  148. count=None
  149. if ret:
  150. for k,v in ret.items():
  151. count=v
  152. return count
  153.  
  154. def insert(self,sql,param=None):
  155. """
  156. 数据库插入
  157. :param sql: SQL语句
  158. :param param: 参数
  159. :return: 受影响的行数
  160. """
  161. return self.execute(sql,param)
  162. def update(self,sql,param=None):
  163. """
  164. 更新操作
  165. :param sql: SQL语句
  166. :param param: 参数
  167. :return: 受影响的行数
  168. """
  169. return self.execute(sql,param)
  170. def delete(self,sql,param=None):
  171. """
  172. 删除操作
  173. :param sql: 删除SQL语句
  174. :param param: 参数
  175. :return: 受影响的行数
  176. """
  177. return self.execute(sql,param)
  178. def batch(self,sql,param=None):
  179. """
  180. 批量插入
  181. :param sql: 插入SQL语句
  182. :param param: 参数
  183. :return: 受影响的行数
  184. """
  185. return self.cursor.executemany(sql,param)
  186. def commit(self,param=None):
  187. """
  188. 提交数据库
  189. :param param:
  190. :return:
  191. """
  192. if param==None:
  193. self.connect.commit()
  194. else:
  195. self.connect.rollback()
  196.  
  197. def close(self):
  198. """
  199. 关闭数据库连接
  200. :return:
  201. """
  202. if self.cursor:
  203. self.cursor.close()
  204. if self.connect:
  205. self.connect.close()
  206. logging.debug("释放数据库连接")
  207. return None

首先我们从配置文件中读取数据库的配置信息,放入dbFactory字典中,一个数据源key对应一个数据库连接池对象

使用
封装好我们的数据库组件后,接下来我们对于数据库的操作就很方便了

注意事项
我们在写SQL语句的时候需要注意我们的参数占位符的使用,注意有两种方式

%s:该方式你可以理解为任意字符,但是我们在参数传递的时候顺序必须正确,否则就会出现结果不一致的情况
%(fied)s:这种方式相对友好一些,我们传入的参数可以是字典对象,而不用关心我们的占位参数是否一致
获取不同的数据源连接
我们上面提到过,我们需要的是一个多数据源的情况,那么我们代码中应该如何使用呢?

  1. # 第一种方式,获取默认数据库的连接,在配置文件中配置名称为master的数据库
  2. connect=MySQLConnect()
  3.  
  4. # 第二种方式,指定key名称获取数据库连接,如下:获取local111的数据库连接
  5. connect=MySQLConnect("local111")

新增数据

新增数据

  1. def insertByIndex():
  2. """
  3. 使用下标索引的方式插入数据
  4. """
  5. sql="insert into user(id,name) values(%s,%s)"
  6. # 获取数据库连接
  7. connect=MySQLConnection()
  8. try:
  9. # 执行插入动作
  10. connect.insert(sql,("","张三"))
  11. # 提交
  12. connect.commit()
  13. except Exception as e:
  14. logging.exception(e)
  15. finally:
  16. # 关闭数据库连接
  17. connect.close()
  18.  
  19. def insertBatchByIndex():
  20. """
  21. 使用下标索引的方式批量插入数据
  22. """
  23. sql="insert into user(id,name) values(%s,%s)"
  24. # 获取数据库连接
  25. connect=MySQLConnection()
  26. try:
  27. # 执行批量插入动作
  28. data=[]
  29. # 放入的是元祖
  30. data.append(("","张三"))
  31. data.append(("","张三2"))
  32. connect.batch(sql,data)
  33. # 提交
  34. connect.commit()
  35. except Exception as e:
  36. logging.exception(e)
  37. finally:
  38. # 关闭数据库连接
  39. connect.close()

看了以上的方式或许你会觉得麻烦,为什么呢,因为我们在开发的时候一般都是使用字典居多,都是key-value的方式,因此使用索引的方式需要我们再申明一个有顺序的元祖对象,很麻烦

使用字典的方式如下:

  1. def insertByDict():
  2. """
  3. 使用下标索引的方式插入数据
  4. """
  5. sql="insert into user(id,name) values(%(id)s,%(name)s)"
  6. # 获取数据库连接
  7. connect=MySQLConnection()
  8. try:
  9. # 执行插入动作
  10. # 此时我们使用的是字典
  11. connect.insert(sql,{"name":"张三","id":""})
  12. # 提交,必须
  13. connect.commit()
  14. except Exception as e:
  15. logging.exception(e)
  16. finally:
  17. # 关闭数据库连接,必须
  18. connect.close()
  19.  
  20. def insertBatchByDict():
  21. """
  22. 使用下标索引的方式批量插入数据
  23. """
  24. sql="insert into user(id,name) values(%(id)s,%(name)s)"
  25. # 获取数据库连接
  26. connect=MySQLConnection()
  27. try:
  28. # 执行批量插入动作
  29. data=[]
  30. # 放入的是自字典
  31. data.append({"name":"张三","id":""})
  32. data.append({"name":"张三1","id":""})
  33. connect.batch(sql,data)
  34. # 提交
  35. connect.commit()
  36. except Exception as e:
  37. logging.exception(e)
  38. finally:
  39. # 关闭数据库连接
  40. connect.close()

以上就是新增的方式,删除和修改同理也差不多.

分页查询数据

比如分页查询的示例:

  1. sql="select id,name,address from restaurant where province=%s "
  2. connect=MySQLConnection()
  3. try:
  4. page=
  5. size=
  6. pagination=connect.listByPage(sql,page,size,'浙江省')
  7. except Exception as e:
  8. logging.exception(e)
  9. finally:
  10. # 关闭数据库连接
  11. 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数据库连接池组件封装(转载)的更多相关文章

  1. DbUtil组件及C3P0数据库连接池组件的使用

    DbUtils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能. 使用c ...

  2. Python MySQL 数据库连接不同方式

    PyMySQL 驱动连接 什么是 PyMySQL?PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb. PyMySQL 遵循 P ...

  3. Python - MySQL 数据库连接 - PyMySQL 驱动 - 第二十五天

    序言 本文我们为大家介绍 Python3 使用 PyMySQL 连接数据库,并实现简单的增删改查. 什么是 PyMySQL? PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务 ...

  4. Python MySQL数据库连接模块

    1. MySQLdb只支持在Python 2版本使用MySQLdb是用于Python链接Mysql数据库的接口.a.pip安装 直接使用pip进行安装,在此之前需要安装一些系统依赖包. ● CentO ...

  5. Python实现Mysql数据库连接池

    python连接Mysql数据库: python编程中可以使用MySQLdb进行数据库的连接及诸如查询/插入/更新等操作,但是每次连接mysql数据库请求时,都是独立的去请求访问,相当浪费资源,而且访 ...

  6. python mysql redis mongodb selneium requests二次封装为什么大都是使用类的原因,一点见解

    1.python mysql  redis mongodb selneium requests举得这5个库里面的主要被用户使用的东西全都是面向对象的,包括requests.get函数是里面每次都是实例 ...

  7. [转载]linux+nginx+python+mysql安装文档

    原文地址:linux+nginx+python+mysql安装文档作者:oracletom # 开发包(如果centos没有安装数据库服务,那么要安装下面的mysql开发包) MySQL-devel- ...

  8. 10分钟教你Python+MySQL数据库操作

    欲直接下载代码文件,关注我们的公众号哦!查看历史消息即可! 本文介绍如何利用python来对MySQL数据库进行操作,本文将主要从以下几个方面展开介绍: 1.数据库介绍 2.MySQL数据库安装和设置 ...

  9. mysql数据库连接池使用(三)数据库元数据信息反射数据库获取数据库信息

    1.1. mysql数据库连接池使用(三)数据库元数据信息反射数据库获取数据库信息 有时候我们想要获取到数据库的基本信息,当前程序连接的那个数据库,数据库的版本信息,数据库中有哪些表,表中都有什么字段 ...

随机推荐

  1. 七、Vue组件库:Element、Swiper(轮播专用组件)

    一.vue的Element组件库 官网:https://element.eleme.cn/#/zh-CN 1.1安装 推荐安装方法: 首先要进入项目目录 cnpm i element-ui -S 或 ...

  2. msf自动连接postgresql配置

    今天做了一下msf连接数据库的配置,中间碰到了一些坑点这里就不详细叙述了,开始正确的操作方式. 首先对postgresql进行配置以方便连接. root@kali:~# service postgre ...

  3. POJ 2309:BST lowbit

    BST Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9140   Accepted: 5580 Description C ...

  4. 活动目录对象属性批量修改工具------ADModify

    最近下载了一个可以修改活动目录用户.组.联系人等活动目录对象属性的工具,试用了一下,发现还是蛮好用的,并且还可以修改对象的扩展属性,如:在活动目录中安装了Exchange 2003,Exchange ...

  5. Rabbitmq之高级特性——实现消费端限流&NACK重回队列

    如果是高并发下,rabbitmq服务器上收到成千上万条消息,那么当打开消费端时,这些消息必定喷涌而来,导致消费端消费不过来甚至挂掉都有可能. 在非自动确认的模式下,可以采用限流模式,rabbitmq ...

  6. 2 —— js语法 —— 对象和方法的声明 。变量提升。闭包

    一,声明对象 var obj1 = {}; var obj2 = {name:'kk',age:18,fun:function{          // name,age,fun为对象的属性,只是属性 ...

  7. java核心-多线程-零碎知识收集

    1.不能使用Integer作为并发锁 原因:synchronized(Integer)时,当值发生改变时,基本上每次锁住的都是不同的对象实例,想要保证线程安全,推荐使用AtomicInteger之类会 ...

  8. 069-PHP数组下标

    <?php $arr=array(98,'hello',67,'A',85,NULL); //定义一个数组 $x=0; //定义三个作为下标的变量 $y=3; $z=5; echo " ...

  9. HDU 4866 多校1 主席树+扫描线

    终于是解决了这个题目了 不过不知道下一次碰到主席树到底做不做的出来,这个东西稍微难一点就不一定能做得出 离散化+扫描线式的建树,所以对于某个坐标二分找到对应的那颗主席树,即搜索出结果即可(因为是扫描线 ...

  10. springboot启动项目报错:ERROR:o.s.b.d.LoggingFailureAnalysisReporter解决办法

    原因是引入了spring security的依赖,将spring security对应的依赖删除即可. 具体可参照: https://blog.csdn.net/qq_37887131/article ...