✍ 此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版,拥抱Vue3.0将前端框架替换成字节最新开源的arco.design,其中约60%重构和20%新增内容,定位为从 0-1手把手实现简单的测试平台开发教程,内容将囊括基础、扩展和实战,由浅入深带你实现测试开发岗位中平台工具技术能力入门和提升。
本篇需要提前准备的环境和开发内容:
- 准备数据库,Mysql5.7 本地或云服务均可
- 实现后端接口服务的数据库操作
产品数据持久化
在项目管理中,真正的数据需要持久化操作的,这里必然就离不开数据库,本项目使用的Mysql数据库,但不会过多的讲解SQL的内容,只会重点讲解后端服务中Python对于数据库的操作相关知识点。
数据库和产品表初始化
使用数据库IDE工具链接mysql数据库,并创建一个数据库TPMStore和一个Products表,字段分别如下
使用Navicat可视化创建,或查看笔者大奇之前分享过的一个好用的开源Beekeeper工具
这里给出SQL语句方便进行表格创建,顺便添加两条正式测试数据
代码语言:javascript复制SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for products
-- ----------------------------
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号自增',
`keyCode` varchar(200) NOT NULL COMMENT '项目唯一编号',
`title` varchar(200) NOT NULL COMMENT '中文项目名',
`desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '描述',
`operator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作者',
`update` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '操作时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='项目产品表';
-- ----------------------------
-- Records of products
-- ----------------------------
BEGIN;
INSERT INTO `products` VALUES (1, 'data', '数据大盘', '内部一个数据技术分析的项目,用于分析各种数据聚合平台', 'daqi', '2021-07-17 20:38:37');
INSERT INTO `products` VALUES (2, 'payment', '收银台', '支付聚合收银台', 'lili', '2021-07-17 20:40:29');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
产品查询接口改造
之前的接口 /api/product/list 是硬编码返回,我们这里需要改造成通过数据库查询获得。
python实现mysql的数据的方式目前支持度较好的有:
- mysqlclient (Star 2.1K )
- PyMySQL(Star 7K )
- mysql.connector (Mysql官方的驱动库)
以上 github star 数据统计于 2022/07/10
综合使用度和后续可能使用ORM(对象关系映射)优化,本项目选择PyMySQL
代码语言:javascript复制# 安装依赖包
python3 -m pip install PyMySQL
然后主要就是引入包,实现数据库的连接和查询操作
代码语言:javascript复制# -*- coding:utf-8 -*-
from flask import Blueprint
import pymysql.cursors
app_product = Blueprint("app_product", __name__)
# 使用用户名密码创建数据库链接
connection = pymysql.connect(host='localhost', # 数据库IP地址或链接域名
user='root', # 设置的具有增改查权限的用户
password='******', # 用户对应的密码
database='TPMStore',# 数据表
charset='utf8mb4', # 字符编码
cursorclass=pymysql.cursors.DictCursor) # 结果作为字典返回游标
@app_product.route("/api/product/list",methods=['GET'])
def product_list():
# 使用python的with..as控制流语句(相当于简化的try except finally)
with connection.cursor() as cursor:
# 查询产品信息表-按更新时间新旧排序
sql = "SELECT * FROM `Products` ORDER BY `Update` DESC"
cursor.execute(sql)
data = cursor.fetchall()
# 按返回模版格式进行json结果返回
resp_data = {
"code": 20000,
"data": data
}
return resp_data
对改造的后的接口用Postman做个验证测试,从下图可以看到数据已经是从product表里查出来的。
PyMySQL使用
PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库。
- 官方文档 https://pymysql.readthedocs.io
- 菜鸟教程:https://www.runoob.com/python3/python3-mysql.html
依赖安装
首先关于安装依赖,上边已经给列出通过$ python3 -m pip install PyMySQL
命令,这里需要特别强调一下,如果你使用的是Mysql 8.x 数据库服务,由于高版本改变了密码加密方式,所以必须安装额外的依赖
# 不兼容加密方式连接报错如下
# RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods
$ python3 -m pip install PyMySQL[rsa]
另外还可以通过改mysql的加密方式为 mysql_native_password
,笔者本地版本8.0.25
为了方便已经修改了,查询的方法见截图:
数据库连接
连接实例的是在代码中import pymysql
后通过.connet(...)
方法创建,扒一下源码可以看到有很到参数
这里捡一些基本的和可能用到的参数做下解释说明
- host 数据库地址IP或者域名
- user 数据库分配的账号
- password 数据库分配的密码
- database 指定数据库, 可以为None后续使用时候进行切换
- port 数据库端口号,默认3306
- read_timeout 读操作超时时间
- write_timeout 写操作超时时间
- charset 字符编码中文建议设置utf8等
- cursorclass 设置返回的数据类型,默认查询返回的数据是tuples元组,一般我们数据多数以table的形式呈现,所以建议设置成
cursorclass=MySQLdb.cursors.DictCursor
字典类型h - connect_timeout 连接超时时间
还有其他如ssl加密相关、连接数设置等,实际项目中按需查阅参数配置。
另外一点在创建db对象后,其实就可以通过游标创建对应的数据库以及切换对应的库。
代码语言:javascript复制# 执行创建数据库
cursor.execute("CREATE DATABASE QiDBTest character SET utf8mb4;")
# 切库或使用 db.select_db("数据库名")
cursor.execute("use QiDBTest;")
# #可以通过以下语句进行创建查询
# cursor.execute("SHOW DATABASES;")
# print(cursor.fetchall())
数据库表操作
创建数据库连接对象,然后再创建一个游标对象cursor
,通过cursor.excute()
执行对应的语句,就可以进行表相关、数据相关操作,其实excute的操作,你完全可以被看做使用任何一个数据库IDE工具,打开了一个查询面板来执行对应的SQL语句
表创建和数据查询 均通过执行对应的SQL语句实现,其中查询结果还需要通过cursor.fetchall()
获取,对应的还有两个常用的
- cursor.fetchone() 返回一行数据
- cursor.fetchmany(size) 返回指定数量行
import pymysql
# 创建数据库连接
db = pymysql.connect(host='localhost',
user='mrzcode',
password='mrzcode',
database='QiDBTest')
# 使用cursor()方法创建一个游标对象 cursor
cursor = db.cursor()
# 使用execute()方法执行 SQL,如果表存在则删除
cursor.execute("DROP TABLE IF EXISTS QiTableDemo")
# 创建表语句
sqlCreateTable = """
CREATE TABLE `QiTableDemo` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(100) NOT NULL COMMENT '名称',
`desc` varchar(500) COMMENT '描述',
PRIMARY KEY (`id`)
)"""
# 执行SQL语句创建表
cursor.execute(sqlCreateTable)
# 验证查询下表情况
cursor.execute("SHOW TABLES;")
print(cursor.fetchall()) # (('qitabledemo',),) 默认元组查询表列表
# 查询QiTableDemo表所有数据
sqlSelect = "SELECT * FROM QiTableDemo;"
# 执行表查询语句
cursor.execute(sqlSelect)
print(cursor.fetchall()) # () 新表返回一个空的tuples
表数据增删改 额外在execute基础上进行db.commit()
提交,如果不提交连接关闭后这些数据修改是不生效的。
import pymysql
# 创建数据库连接
db = pymysql.connect(host='127.0.0.1',
user='root',
password='rox@123',
database='QiDBTest',
cursorclass=pymysql.cursors.DictCursor)
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
sqlInsert = '''INSERT INTO qitabledemo(`name`,`desc`) VALUES ('插入测试名称', '插入测试描述');'''
# 执行表查询语句
cursor.execute(sqlInsert)
# 对执行提交,这里可以尝试注释掉验证不进行提交数据能否插入
db.commit()
# 查询数据是否正确插入
cursor.execute("select * from qitabledemo;")
print(cursor.fetchall()) # [{'id': 6, 'name': '插入测试名称', 'desc': '插入测试描述'}]
# 关闭数据库连接
db.close()
上边这种sql语句是一个字符串形式,但实际在代码逻辑处理中值一般都是通过变量传递的,所以通过以下两种方式动态赋值
代码语言:javascript复制# 方式一:占位拼接字符串
sqlMethod1 = "INSERT INTO qitabledemo(`name`,`desc`) VALUES ('%s', '%s')" % ("占位名称","占位描述")
cursor.execute(sqlMethod1)
# 方式二:通过execute传参
sqlMethod2 = "INSERT INTO qitabledemo(`name`,`desc`) VALUES ('%s', '%s')"
cursor.execute(sqlMethod1,(变量1,变量2))
剩下关于更新、删除的操作同样,只是按需替换成对应的语句,但强调的一点是不要忘记commit
,以下给出我这边的例子和验证测试
事务和错误处理
关于事务机制 可以确保数据一致性,场景主要用于多逻辑交互时候其中操作错误,进行响应的回滚处理,避免产生脏数据,事务通常具有4个属性:原子性、一致性、隔离性、持久性。 对于支持事务的数据库, 在Python数据库编程中,当游标建立之时,就自动开始了一个隐形的数据库事务。
- commit() 方法游标的所有更新操作;
- rollback() 方法回滚当前游标的所有操作。
每一个方法都开始了一个新的事务。
代码语言:javascript复制sql = "数据库操作的增删改查语句"
try:
# 执行SQL语句
cursor.execute(sql)
# 向数据库提交
db.commit()
except:
# 发生错误时回滚
db.rollback()
关于错误 DB API中定义了一些数据库操作的错误及异常(以下引用菜鸟教程),严谨的编程需要对不同的错误进行响应的处理。
异常 | 描述 |
---|---|
Warning | 当有严重警告时触发,例如插入数据被截断等等。必须是 StandardError 的子类。 |
Error | 警告以外所有其他错误类。必须是 StandardError 的子类。 |
InterfaceError | 当有数据库接口模块本身的错误(而不是数据库的错误)发生时触发。必须是Error的子类。 |
DatabaseError | 和数据库有关的错误发生时触发。必须是Error的子类。 |
DataError | 当有数据处理时的错误发生时触发,例如:除零错误,数据超范围等等。必须是DatabaseError的子类。 |
OperationalError | 指非用户控制的,而是操作数据库时发生的错误。例如:连接意外断开、 数据库名未找到、事务处理失败、内存分配错误等等操作数据库发生的错误。必须是DatabaseError的子类。 |
IntegrityError | 完整性相关的错误,例如外键检查失败等。必须是DatabaseError子类。 |
InternalError | 数据库的内部错误,例如游标(cursor)失效了、事务同步失败等等。必须是DatabaseError子类。 |
ProgrammingError | 程序错误,例如数据表(table)没找到或已存在、SQL语句语法错误、 参数数量错误等等。必须是DatabaseError的子类。 |
NotSupportedError | 不支持错误,指使用了数据库不支持的函数或API等。例如在连接对象上 使用.rollback()函数,然而数据库并不支持事务或者事务已关闭。必须是DatabaseError的子类。 |
新手操作指南
最后总结一下一般Python使用PyMySQL的编程步骤
- 引用模块库
- 创建连接对象db=connect(...)
- 从连接对象获取游标cursor=db.cursor()
- 准备sql语句并通过游标执行cursor.execute(sql)
- 如果是非查询动作还需要db.commit()
- 关闭数据库连接db.close()
以上就是本篇的主要内容,重点讲解Python 对mysql数据库的操作,并且开始就开门见山地做个了项目实战,相信这些内容掌握了,本系列项目中有关数据操作部分都会游刃有余。
上篇回顾:测试需求平台8:Acro Vue页面创建及菜单路由讲解
下篇预告:产品服务管理接口实现