pymysql的使用

pymysql的使用

1 驱动

MySQL基于TCP协议之上开发,但是网络连接后,传输的数据必须遵循MySQL的协议。
封装好MySQL协议的包,就是驱动程序。

MySQL的驱动:

  • MySQLdb: 最有名的库。对MySQL的C Client封装实现,支持Python2,不更新了,不支持Python3

  • MySQL官方Connector

  • pymysql: 语法兼容MySQLdb,使用Python写的库,支持Python3

2 pymysql的使用

连接数据库pymysql.connect方法,返回Connections模块下的Connection类的实例。

  • Connection类的事务管理:Connection.begin,开始事务, Connection.commit,提交, Connection.rollback,回滚。

游标cursor:操作数据库必须使用游标。需先获取一个游标对象:

  • Connection.cursor(cursor=None)方法返回一个新的游标对象: cursor参数,可以指定一个Cursor类,比如DictCursor类,默认为Cursor类。
  • Cursor类:Cursor.fetchone,获取结果集的下一行;Cursor.fetchmang,获取结果集的指定行数;Cursor.fetchall,返回结果集的所有行。
  • DictCursor类:会将查询数据库结果集的每一行转换为字典,key为列名,value为值。

注意: Cursor的fetch操作是结果集,结果集是保存在客户端的,也就是说fetch的时候,查询已经结束了。

数据库交互的一般流程:
建立连接 – 获取游标 – 执行sql – 提交事务 – 释放资源

import pymysql
from pymysql.cursors import DictCursordef update_database():global connconn = Nonecursor = Nonetry:# 建立连接, 支持上下文with pymysql.connect(host="127.0.0.1", user="root", password="cli*963.", database="test") as conn:print(conn.ping(False))  # 测试数据库连接是否活着;参数reconnect,表示如果是断开时,是否重连# 获取一个cursorcursor = conn.cursor()for i in range(10):  # 批量提交,一般commit一般放到最后统一commit,效率更高。sql = "insert into tee values (12, 'zhonghua_{}', 21)".format(i)res = cursor.execute(sql)print(res)conn.commit()  # connection默认不commit:autocommit=Falseexcept Exception as err:print(err)conn.rollback()  # 异常回滚finally:if cursor:cursor.close()def get_database():sql = "select * from tee"try:with pymysql.connect(host="127.0.0.1", user="root", password="cli*963.", database="test") as _conn:with _conn.cursor() as cursor:line = cursor.execute(sql)print(line)print(cursor.fetchone())print(cursor.fetchone())print(cursor.fetchmany(2))print(cursor.fetchmany(2))print(cursor.fetchall())print(cursor.rownumber)cursor.rownumber = 0  # 改变游标位置,指向初始位置cursor.rownumber = -2  # 支持负向索引print(cursor.fetchone())print(cursor.rowcount)  # 返回总行数# fetch操作的是结果集,结果集是保存在客户端的,也就是说fetch的时候,查询结果已经结束了。print("*---------------------------*")with _conn.cursor(cursor=DictCursor) as cursor:  # Cursor类有一个Mixin的子类DictCursor,将返回结果保证为dictcursor.execute(sql)print(cursor.fetchone())print(cursor.fetchone())print(cursor.fetchmany(2))print(cursor.fetchmany(2))print(cursor.fetchall())except Exception as err:print("error:", err)

3 sql注入攻击

什么是SQL注入攻击:
猜测后台数据库的查询语句使用拼接字符串的方式,从而经过设计为服务端传参,令其拼接出特殊字符串,返回用户想要的结果。

例如:使用字符串拼接sql语句select * from tee where id={}".format("10 or 1=1")进行查询。结果为select * from tee where id=10 or 1=1,where子句永远为真,导致整个表格被查出来。

永远不要相信客户端传来的数据是规范的及安全的!!!

如何解决注入攻击?
参数化查询,可以有效防止注入攻击,并提高查询的效率。Cursor.execute(query, args=None)

  • args,必须是元组、列表或字典。如果查询字符串使用%(name)s,就必须使用字典。
import pymysql
from pymysql.cursors import DictCursordef sql_injection_test():sql = "select * from tee where id={}".format("10 or 1=1")  # 字符串拼接,使where子句永远为真,导致整个表格被查出来。sql1 = "select * from tee where id=%s"# 解决注入攻击:参数化查询,可以有效防止注入攻击,并提高查询的效率try:with pymysql.connect(host="127.0.0.1", user="root", password="cli*963.", database="test") as _conn:with _conn.cursor(DictCursor) as cursor:cursor.execute(sql)  # 导致注入攻击print("aaaaaaaaaaaaaaa")print(cursor.fetchall())args = ("10 or 1=1",)cursor.execute(sql1, args=args)  # 参数化查询防止sql注入。 args可以是元组、列表、字典;为字典时,sql1 查询字符串必须是%(name)s格式print("bbbbbbbbbbbbbbb")print(cursor.fetchall())except Exception as err:print(err)

参数化查询为什么提高效率?
原因就是–SQL语句缓存。
数据库服务器一般会对SQL语句编译和缓存,编译只对SQL语句部分,所以参数中就算有SQL指令也不会被执行。

编译过程,需要词法分析、语法分析、生成AST、优化、生成执行计划等过程,比较耗费资源。服务端会先查找是否对同一条查询语句进行了缓存,如果缓存未失效,则不需要再次编译,从而降低了编译的成本,降低了内存消耗。

可以认为SQL语句字符串就是一个key,如果使用拼接方案,每次发过去的SQL语句都不一样,都需要编译并缓存。

大量查询的时候,首选使用参数化查询,以节省资源。

开发时,应该使用参数化查询。

注意:这里说的是查询字符串的缓存,不是查询结果的缓存。

4 pysql连接池实现

设计一个连接池:可以设置池大小的容器,连接池存放着数据库的连接。使用时,从池中获取一个连接,用完归还。从而减少频繁的创建、销毁数据库连接的过程,提高性能。

设计:

  • 设计一个池对象ConnPool。构建时,传入连接数据库的相关参数(用户名、密码、主机、端口、数据库名)。
  • 考虑多线程使用
  • 使用get从池中拿走一个连接,用完归还。
import queue
import threading
import time
import loggingimport pymysql
from pymysql.cursors import DictCursorlogging.basicConfig(level=logging.INFO)class ConnPool:def __init__(self, size: int = 10, *, host: str, user: str, password: str, database: str, **kwargs):if not isinstance(size, int) or size < 1:size = 10self.size = sizeself._pool = queue.Queue()  # 使用队列作为连接池的容器。get时有连接,则获取,否则阻塞。for _ in range(size):self._pool.put(pymysql.connect(host=host, user=user, password=password, database=database, **kwargs))self.local = threading.local()  # 使用threading.local,记录每一个线程获取的连接实例,用完归还def get_conn(self):# 一个线程多次拿连接场景,单个线程未归还只能拿同一个,保证threading.local.conn记录的是同一个连接if getattr(self.local, "conn", None) is None:_conn = self._pool.get()self.local.conn = _connreturn self.local.conndef return_conn(self, _conn: pymysql.connect):if isinstance(_conn, pymysql.connect):self._pool.put(_conn)self.local.conn = None  # 归还连接后,threading.local应置为None# threading.local只能解决不同线程使用conn的问题,线程内必须同步方式使用,自动拿连接并规划,自动提交或回滚,避免线程内多次拿连接,或update多次后没有commit# 通过上下文,实现自动连接、自动提交或回滚,并归还连接。def __enter__(self):return self.get_conn()def __exit__(self, exc_type, exc_val, exc_tb):# __exit__前,不知道归还的连接是哪一个,正好使用threading.local,记录当前线程获取的是哪一个连接if exc_type:  # 存在异常,回滚self.local.conn.rollback()else:  # 没有异常,提交self.local.conn.commit()self.return_conn(self.local.conn)def foo(_pool: ConnPool):# conn = _pool.get_conn()time.sleep(3)with _pool as cur_conn:  # 使用连接池的上下文with cur_conn.cursor(DictCursor) as cursor:cursor.execute("select * from tee where id=%s", args=(10,))logging.info("{}:{}".format(threading.current_thread().name, cursor.rowcount))for column in cursor:  # cursor是一个可迭代对象,迭代的是查询的每一条记录logging.info("{}:{}".format(threading.current_thread().name, column))if __name__ == '__main__':# update_database()# get_database()# sql_injection_test()pool = ConnPool(host="127.0.0.1", user="root", password="cli*963.", database="test")# 连接池连接获取的游标cursor不能跨线程使用,因为线程A用完cursor可能关闭,而线程B还没使用,这时候会抛异常。# 使用队列实现线程池,也可以改用信号量来实现。for i in range(8):threading.Thread(target=foo, args=(pool,), name="foo_{}".format(i)).start()

该连接池存在的问题:

  • 连接池连接获取的游标cursor不能跨线程使用,因为线程A用完cursor可能关闭,而线程B还没使用,这时候会抛异常。
  • 使用队列实现线程池,也可以改用信号量来实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/56463.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于PreparedStatement抓取带参最终SQL(oracle,mysql,PostgreSQL等通用)

前言 很多抓取最终SQL的方法&#xff0c;都是带着?的。比如&#xff1a; SELECT value from sys_param where name?我们现在想把 &#xff1f; 给去掉。有什么办法呢 方法1 编写工具类 &#xff08;该方法有些情况下是不适用的&#xff0c;比如oracle数据库&#xff0c;该…

探索内网穿透工具:实现局域网SQL Server数据库的公网远程访问方法

文章目录 1.前言2.本地安装和设置SQL Server2.1 SQL Server下载2.2 SQL Server本地连接测试2.3 Cpolar内网穿透的下载和安装2.3 Cpolar内网穿透的注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据库的重要性相信大家都有所了解&…

【mysql事务隔离级别】事务隔离级别(面试高频考点!)

目录 什么是事务的隔离级别&#xff1f; 常见的四种事务隔离级别 读未提交 读已提交 为什么没有解决幻读问题&#xff0c;是怎么导致的&#xff1f; 可重复读 串行化 什么是事务的隔离级别&#xff1f; 事务的隔离级别&#xff08;Isolation Level&#xff09;指的是在并…

下一代存储解决方案:湖仓一体

文章首发地址 湖仓一体是将数据湖和数据仓库相结合的一种数据架构&#xff0c;它可以同时满足大数据存储和传统数据仓库的需求。具体来说&#xff0c;湖仓一体可以实现以下几个方面的功能&#xff1a; 数据集成&#xff1a; 湖仓一体可以集成多个数据源&#xff0c;包括结构…

Spring Cache框架(缓存)

1、介绍&#xff1a; Spring Cache 是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单加个注解&#xff0c;就能实现缓存功能。它提供了一层抽象&#xff0c;底层可以切换不同的cache实现。具体就是通过CacheManager 接口来实现不同的缓存技术。 针对不同…

Pygame编程(4)event模块

Pygame编程&#xff08;4&#xff09;event模块 函数示例 函数 pygame.event.pump 让 Pygame 内部自动处理事件pygame.event.get 从队列中获取事件pygame.event.poll 从队列中获取一个事件pygame.event.wait 等待并从队列中获取一个事件pygame.event.peek 检测某类型事件是否在…

私有化部署即时通讯平台,30分钟替换钉钉和企业微信

随着企业对即时通讯和协作工具的需求不断增长&#xff0c;私有化部署的即时通讯平台成为企业的首选。WorkPlus作为有10余年行业深耕经验与技术沉淀品牌&#xff0c;以其安全高效的私有化部署即时通讯解决方案&#xff0c;帮助企业在30分钟内替换钉钉和企业微信。本文将深入探讨…

JavaWeb学习-Day10

SpringBootWeb案例 准备工作 开发流程&#xff1a; 开发接口步骤&#xff1a; 删除部门&#xff1a; 新增部门&#xff1a; 简化代码&#xff1a; limit:分页展示&#xff0c;公式&#xff1a;&#xff08;页数-1&#xff09;*页面总数&#xff0c;页面总数 目前出现的问题&am…

STM32 CubeMX (H750)RGB屏幕 LTDC

STM32 CubeMX STM32 RGB888 LTDC STM32 CubeMX一、STM32 CubeMX 设置时钟树LTDC使能设置屏幕参数修改RGB888的GPIO 二、代码部分效果 RGB屏幕线束定义&#xff1a; 一、STM32 CubeMX 设置 时钟树 这里设置的时钟&#xff0c;关于刷新速度 举例子&#xff1a;LCD_CLK24MHz 时…

穿越网络迷雾的神奇通道 - WebSocket详解

WebSocket&#xff0c;作为一项前端技术&#xff0c;已经成为现代Web应用不可或缺的一部分。本文将深入解析WebSocket&#xff0c;介绍其工作原理和用途&#xff0c;并通过简单的代码示例&#xff0c;让你对这个神奇的网络通信协议有更深入的了解。 WebSocket是什么&#xff1…

【大数据知识】大数据平台和数据中台的定义、区别以及联系

数据行业有太多数据名词&#xff0c;例如大数据、大数据平台、数据中台、数据仓库等等。但大家很容易混淆&#xff0c;也很容易产生疑问&#xff0c;今天我们就来简单聊聊大数据平台和数据中台的定义、区别以及联系。 大数据平台和数据中台的定义 大数据平台&#xff1a;一个…

Mysql索引+事务+存储引擎

索引 索引的概念 索引是一个排序的列表&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于C语言的链表通过指针指向数据记录的内存地址&#xff09;。 使用索引后可以不用扫描全表来定位某行的数据&#xff0c;而是先通过索引表找…

浅谈 Linux 下 vim 的使用

Vim 是从 vi 发展出来的一个文本编辑器&#xff0c;其代码补全、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。 Vi 是老式的字处理器&#xff0c;功能虽然已经很齐全了&#xff0c;但还有可以进步的地方。Vim 可以说是程序开发者的一项很好用的工…

代码随想录Day_48打卡

①、打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房…

STM32之17.PWM脉冲宽度调制

一LED0脉冲宽度调制在TIM14_CHI&#xff0c;先将LED&#xff08;PF9&#xff09;代码配置为AF推挽输出模式&#xff0c;将PF9引脚连接到TIM14&#xff0c; #include <stm32f4xx.h>static GPIO_InitTypeDef GPIO_InitStruct;void Led_init(void) {//打开端口F的硬件时钟&a…

Yolo系列-yolov2

YOLO-V2 更快&#xff01;更强&#xff01; YOLO-V2-BatchNormalization BatchNormalization&#xff08;批归一化&#xff09;是一个常用的深度神经网络优化技术&#xff0c;它可以将输入数据进行归一化处理&#xff0c;使得神经网络更容易进行学习。在YOLOv2中&#xff0c;B…

《C和指针》笔记11: external和internal链接属性

当组成一个程序的各个源文件分别被编译之后&#xff0c;所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起&#xff0c;形成可执行程序。然而&#xff0c;如果相同的标识符出现在几个不同的源文件中时&#xff0c;它们是像Pascal那样表示同一个实体&#xff1f;…

HashSet 和 TreeSet 的区别

HashSet 和 TreeSet 都是 Java 中的集合类&#xff0c;用于存储一组不重复的元素。它们的主要区别在于内部实现和性能方面。 内部实现&#xff1a; HashSet 使用哈希表实现&#xff0c;通过散列函数将元素存储在数组中&#xff0c;这样可以快速地查找元素。TreeSet 使用红黑树实…

Apache StreamPark系列教程第二篇——项目打包和开发

一、项目打包 项目依赖maven、jdk8.0、前端(node、npm) //下载代码 git clone//maven打包相关内容 mvn -N io.takari:maven:wrapper //前端打包相关内容 curl -sL https://rpm.nodesource.com/setup_16.x | bash - yum -y install nodejs npm -v npm install -g pnpm默认是h2…

手把手教你搭建Serv-U FTP服务器共享文件并实现外网远程访问「无公网IP」

文章目录 1. 前言2. 本地FTP搭建2.1 Serv-U下载和安装2.2 Serv-U共享网页测试2.3 Cpolar下载和安装 3. 本地FTP发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 科技日益发展的今天&#xff0c;移动电子设备似乎成了我们生活的主角&#xff0c;智能…