测试需求平台6-数据持久化与PyMySQL使用

✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版,拥抱Vue3.0将前端框架替换成字节最新开源的arco.design,其中约60%重构和20%新增内容,定位为从 0-1手把手实现简单的测试平台开发教程,内容将囊括基础、扩展和实战,由浅入深带你实现测试开发岗位中平台工具技术能力入门和提升。

本篇需要提前准备的环境和开发内容:

  • 准备数据库,Mysql5.7+本地或云服务均可
  • 实现后端接口服务的数据库操作

1. 产品数据持久化

在项目管理中,真正的数据需要持久化操作的,这里必然就离不开数据库,本项目使用的Mysql数据库,但不会过多的讲解SQL的内容,只会重点讲解后端服务中Python对于数据库的操作相关知识点。

1.1 数据库和产品表初始化

使用数据库IDE工具链接mysql数据库,并创建一个数据库TPMStore和一个Products表,字段分别如下

使用Navicat可视化创建,或查看笔者大奇之前分享过的一个好用的开源Beekeeper工具

这里给出SQL语句方便进行表格创建,顺便添加两条正式测试数据

sql 复制代码
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;

1.2 产品查询接口改造

之前的接口 /api/product/list 是硬编码返回,我们这里需要改造成通过数据库查询获得。

python实现mysql的数据的方式目前支持度较好的有:

  • mysqlclient (Star 2.1K+)
  • PyMySQL(Star 7K+)
  • mysql.connector (Mysql官方的驱动库)

以上 github star 数据统计于 2022/07/10

综合使用度和后续可能使用ORM(对象关系映射)优化,本项目选择PyMySQL

shell 复制代码
# 安装依赖包
python3 -m pip install PyMySQL

然后主要就是引入包,实现数据库的连接和查询操作

shell 复制代码
# -*- 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表里查出来的。

2. PyMySQL使用

PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库。

2.1 依赖安装

首先关于安装依赖,上边已经给列出通过$ python3 -m pip install PyMySQL 命令,这里需要特别强调一下,如果你使用的是Mysql 8.x 数据库服务,由于高版本改变了密码加密方式,所以必须安装额外的依赖

shell 复制代码
# 不兼容加密方式连接报错如下
# 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为了方便已经修改了,查询的方法见截图:

2.2 数据库连接

连接实例的是在代码中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对象后,其实就可以通过游标创建对应的数据库以及切换对应的库。

python 复制代码
# 执行创建数据库
cursor.execute("CREATE DATABASE QiDBTest character SET utf8mb4;") 

# 切库或使用 db.select_db("数据库名")
cursor.execute("use QiDBTest;") 

# #可以通过以下语句进行创建查询
# cursor.execute("SHOW DATABASES;")
# print(cursor.fetchall())

2.3 数据库表操作

创建数据库连接对象,然后再创建一个游标对象cursor,通过cursor.excute() 执行对应的语句,就可以进行表相关、数据相关操作,其实excute的操作,你完全可以被看做使用任何一个数据库IDE工具,打开了一个查询面板来执行对应的SQL语句

表创建和数据查询 均通过执行对应的SQL语句实现,其中查询结果还需要通过cursor.fetchall()获取,对应的还有两个常用的

  • cursor.fetchone() 返回一行数据
  • cursor.fetchmany(size) 返回指定数量行
python 复制代码
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()提交,如果不提交连接关闭后这些数据修改是不生效的。

python 复制代码
import pymysql

# 创建数据库连接
db = pymysql.connect(host='127.0.0.1',
                     user='root****',
                     password='*******',
                     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语句是一个字符串形式,但实际在代码逻辑处理中值一般都是通过变量传递的,所以通过以下两种方式动态赋值

python 复制代码
# 方式一:占位拼接字符串
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,以下给出我这边的例子和验证测试

2.4 事务和错误处理

**关于事务机制 **可以确保数据一致性,场景主要用于多逻辑交互时候其中操作错误,进行响应的回滚处理,避免产生脏数据,事务通常具有4个属性:原子性、一致性、隔离性、持久性。

对于支持事务的数据库, 在Python数据库编程中,当游标建立之时,就自动开始了一个隐形的数据库事务。

  • commit() 方法游标的所有更新操作;
  • rollback() 方法回滚当前游标的所有操作。

每一个方法都开始了一个新的事务。

python 复制代码
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的子类。

2.6 新手操作指南

最后总结一下一般Python使用PyMySQL的编程步骤

  1. 引用模块库
  2. 创建连接对象db=connect(...)
  3. 从连接对象获取游标cursor=db.cursor()
  4. 准备sql语句并通过游标执行cursor.execute(sql)
  5. 如果是非查询动作还需要db.commit()
  6. 关闭数据库连接db.close()

以上就是本篇的主要内容,重点讲解Python 对mysql数据库的操作,并且开始就开门见山地做个了项目实战,相信这些内容掌握了,本系列项目中有关数据操作部分都会游刃有余。

相关推荐
惊鸿一博23 分钟前
mysql_page pagesize 如何实现游标分页?
数据库·mysql
不学习何以强国1 小时前
Cool Unix + OpenAuth.Net 实现一款校园小程序的开发
mysql·前端框架·asp.net
海奥华211 小时前
SQLEXPLAIN 详解
数据库·mysql
情深不寿31712 小时前
MySQL————数据库基础
数据库·mysql
程序新视界12 小时前
如何选择合适的数据库?PostgreSQL与MySQL各项对比
数据库·mysql·postgresql
dongchen。15 小时前
MySQL第一次作业
数据库·mysql
重生之我是Java开发战士16 小时前
【MySQL】数据库基础
数据库·mysql
ChuHsiang16 小时前
【剑指MySQL】数据库基础(1)
数据库·mysql
九皇叔叔17 小时前
Docker 镜像维护指南:从配置优化到 MySQL 实战运行
mysql·adb·docker
muxin-始终如一17 小时前
MySQL分区分表实现方法详解
数据库·mysql·adb