- MySQLdb(目前仅支持python2.x)
2.ORM框架
- SQLAchemy
2.1 PyMySQL模块
本文主要介绍PyMySQL模块,MySQLdb使用方式类似
2.1.1 安装PyMySQL
PyMySQL是一个Python编写的MySQL驱动程序,让我们可以用Python语言操作MySQL数据库。
pip install PyMySQL
2.2 基本使用
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
import pymysql
创建连接
conn = pymysql.connect(host=“127.0.0.1”, port=3306, user=‘zff’, passwd=‘zff123’, db=‘zff’, charset=‘utf8mb4’)
创建游标(查询数据返回为元组格式)
cursor = conn.cursor()
创建游标(查询数据返回为字典格式)
cursor = conn.cursor(pymysql.cursors.DictCursor)
1. 执行SQL,返回受影响的行数
effect_row1 = cursor.execute(“select * from USER”)
2. 执行SQL,返回受影响的行数,一次插入多行数据
effect_row2 = cursor.executemany(“insert into USER (NAME) values(%s)”, [(“jack”), (“boom”), (“lucy”)]) # 3
查询所有数据,返回数据为元组格式
result = cursor.fetchall()
增/删/改均需要进行commit提交,进行保存
conn.commit()
关闭游标
cursor.close()
关闭连接
conn.close()
print(result)
“”"
[{‘id’: 6, ‘name’: ‘boom’}, {‘id’: 5, ‘name’: ‘jack’}, {‘id’: 7, ‘name’: ‘lucy’}, {‘id’: 4, ‘name’: ‘tome’}, {‘id’: 3, ‘name’: ‘zff’}, {‘id’: 1, ‘name’: ‘zhaofengfeng’}, {‘id’: 2, ‘name’: ‘zhaofengfeng02’}]
“”"
2.3 获取最新创建的数据自增ID
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
import pymysql
创建连接
conn = pymysql.connect(host=“127.0.0.1”, port=3306, user=‘zff’, passwd=‘zff123’, db=‘zff’, charset=‘utf8mb4’)
创建游标(查询数据返回为元组格式)
cursor = conn.cursor()
获取新创建数据自增ID
effect_row = cursor.executemany(“insert into USER (NAME)values(%s)”, [(“eric”)])
增删改均需要进行commit提交
conn.commit()
关闭游标
cursor.close()
关闭连接
conn.close()
new_id = cursor.lastrowid
print(new_id)
“”"
8
“”"
2.4 查询操作
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
import pymysql
创建连接
conn = pymysql.connect(host=“127.0.0.1”, port=3306, user=‘zff’, passwd=‘zff123’, db=‘zff’, charset=‘utf8mb4’)
创建游标
cursor = conn.cursor()
cursor.execute(“select * from USER”)
获取第一行数据
row_1 = cursor.fetchone()
获取前n行数据
row_2 = cursor.fetchmany(3)
# 获取所有数据
row_3 = cursor.fetchall()
关闭游标
cursor.close()
关闭连接
conn.close()
print(row_1)
print(row_2)
print(row_3)
⚠️ 在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:
- cursor.scroll(1,mode=‘relative’) # 相对当前位置移动
- cursor.scroll(2,mode=‘absolute’) # 相对绝对位置移动
2.5 防止SQL注入
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
import pymysql
创建连接
conn = pymysql.connect(host=“127.0.0.1”, port=3306, user=‘zff’, passwd=‘zff123’, db=‘zff’, charset=‘utf8mb4’)
创建游标
cursor = conn.cursor()
存在sql注入情况(不要用格式化字符串的方式拼接SQL)
sql = “insert into USER (NAME) values(‘%s’)” % (‘zhangsan’,)
effect_row = cursor.execute(sql)
正确方式一
execute函数接受一个元组/列表作为SQL参数,元素个数只能有1个
sql = “insert into USER (NAME) values(%s)”
effect_row1 = cursor.execute(sql, [‘wang6’])
effect_row2 = cursor.execute(sql, (‘wang7’,))
正确方式二
sql = “insert into USER (NAME) values(%(name)s)”
effect_row1 = cursor.execute(sql, {‘name’: ‘wudalang’})
写入插入多行数据
effect_row2 = cursor.executemany(“insert into USER (NAME) values(%s)”, [(‘ermazi’), (‘dianxiaoer’)])
提交
conn.commit()
关闭游标
cursor.close()
关闭连接
conn.close()
这样,SQL操作就更安全了。如果需要更详细的文档参考PyMySQL文档吧。不过好像这些SQL数据库的实现还不太一样,PyMySQL的参数占位符使用%s这样的C格式化符,而Python自带的sqlite3模块的占位符好像是问号(?)。因此在使用其他数据库的时候还是仔细阅读文档吧。Welcome to PyMySQL’s documentation
三. 数据库连接池
上文中的方式存在一个问题,单线程情况下可以满足,程序需要频繁的创建释放连接来完成对数据库的操作,那么,我们的程序/脚本在多线程情况下会引发什么问题呢?此时,我们就需要使用数据库连接池来解决这个问题!
3.1 DBUtils模块
DBUtils是Python的一个用于实现数据库连接池的模块。
此连接池有两种连接模式:
- 为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接才会自动关闭
- 创建一批连接到连接池,供所有线程共享使用(推荐使用)
3.2 模式一
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
from DBUtils.PersistentDB import PersistentDB
import pymysql
POOL = PersistentDB(
creator=pymysql, # 使用链接数据库的模块
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。如:[“set datestyle to …”, “set time zone …”]
ping=0,
ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
closeable=False,
如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
threadlocal=None, # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
host=‘127.0.0.1’,
port=3306,
user=‘zff’,
password=‘zff123’,
database=‘zff’,
charset=‘utf8’,
)
def func():
conn = POOL.connection(shareable=False)
cursor = conn.cursor()
cursor.execute(‘select * from USER’)
result = cursor.fetchall()
cursor.close()
conn.close()
return result
result = func()
print(result)
3.2 模式二
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
import time
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
POOL = PooledDB(
creator=pymysql, # 使用链接数据库的模块
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5, # 链接池中最多闲置的链接,0和None不限制
maxshared=3,
链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。如:[“set datestyle to …”, “set time zone …”]
ping=0,
ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
host=‘127.0.0.1’,
port=3306,
user=‘zff’,
password=‘zff123’,
database=‘zff’,
charset=‘utf8’
)
def func():
检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常
否则
则优先去初始化时创建的链接中获取链接 SteadyDBConnection。
然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。
如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。
一旦关闭链接后,连接就返回到连接池让后续线程继续使用。
conn = POOL.connection()
print(‘连接被拿走了’, conn._con)
print(‘池子里目前有’, POOL._idle_cache, ‘\r\n’)
cursor = conn.cursor()
cursor.execute(‘select * from USER’)
result = cursor.fetchall()
conn.close()
return result
result = func()
print(result)
⚠️ 由于pymysql、MySQLdb等threadsafety值为1,所以该模式连接池中的线程会被所有线程共享,因此是线程安全的。如果没有连接池,使用pymysql来连接数据库时,单线程应用完全没有问题,但如果涉及到多线程应用那么就需要加锁,一旦加锁那么连接势必就会排队等待,当请求比较多时,性能就会降低了。
3.3 加锁
#! /usr/bin/env python
-*- coding: utf-8 -*-
author = “shuke”
Date: 2018/5/13
import pymysql
import threading
from threading import RLock
LOCK = RLock()
CONN = pymysql.connect(host=‘127.0.0.1’,
port=3306,
user=‘zff’,
password=‘zff123’,
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数软件测试工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
4Z0P-1712984071642)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-9T0bejfV-1712984071643)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!