一、引言:为什么 pymysql 是 Python 操作 MySQL 的首选
在 Python 后端开发、数据分析、自动化运维等场景中,MySQL 是最常用的关系型数据库 ,而 pymysql 作为纯 Python 实现的 MySQL 客户端库,无需依赖 MySQL C 语言库,跨平台兼容性强、安装便捷、API 简洁易用,已成为 Python 操作 MySQL 的标准第三方库。
1.1 背景与意义
- 纯 Python 实现,兼容 Python 3.6+ 所有版本,支持 MySQL 5.5+、8.0+ 全版本
- 替代老旧的
MySQLdb,解决 Python3 兼容性问题,是 Django、Flask 等框架的底层依赖 - 支持事务、存储过程、批量操作、连接池等企业级特性,满足生产环境需求
- 轻量高效,单线程并发场景性能优异,学习成本低,适合新手入门与实战开发
据统计,超过 80% 的 Python MySQL 项目使用 pymysql,其生态完善、文档丰富,是后端开发者必须掌握的核心模块。
1.2 本章结构概览
plaintext
📊 模块介绍 → 安装配置 → 基础连接 → 核心操作 → 高级特性 → 实战案例 → 最佳实践 → 常见问题 → 总结展望
二、核心概念解析
2.1 基本定义
概念一:pymysql 核心特性
表格
| 特性 | 说明 | 应用场景 |
|---|---|---|
| 纯 Python 实现 | 无 C 依赖,跨平台 | Windows/Linux/Mac 全场景使用 |
| 兼容 MySQL 协议 | 支持 5.5/5.7/8.0 全版本 | 新旧项目无缝迁移 |
| 完整 CRUD 支持 | 增删改查原生支持 | 常规业务数据操作 |
| 事务管理 | 提交 / 回滚 / 保存点 | 金融、订单等强一致性场景 |
| 连接池适配 | 兼容 DBUtils 连接池 | 高并发 Web 服务 |
| 数据类型映射 | 自动转换 Python/MySQL 类型 | 简化数据处理 |
概念二:MySQL 基础连接要素
- 主机(host) :MySQL 服务地址,本地为
localhost/127.0.0.1,远程为服务器 IP - 端口(port) :MySQL 默认端口
3306 - 用户名(user) :数据库登录账号,如
root - 密码(password):数据库登录密码
- 数据库名(database):要操作的目标数据库
- 字符集(charset) :推荐
utf8mb4,支持 emoji 与全字符集
2.2 关键术语解释
- 连接对象(Connection):Python 与 MySQL 建立的通信通道,所有操作基于此对象
- 游标对象(Cursor):执行 SQL 语句、获取结果集的工具,类似操作手柄
- 事务(Transaction):一组 SQL 操作的原子性单元,要么全部执行,要么全部回滚
- 上下文管理器(with):自动管理连接 / 游标关闭,避免资源泄漏
- 参数化查询:防止 SQL 注入的安全查询方式,核心生产环境必用
2.3 技术架构概览
plaintext
┌─────────────────────────────────────────┐
│ 应用层 (Python) │
│ 业务代码 + 调用 pymysql │
├─────────────────────────────────────────┤
│ pymysql 核心层 │
│ 连接管理 + 游标操作 + 协议解析 │
├─────────────────────────────────────────┤
│ MySQL 服务层 │
│ 数据库实例 + 数据表 + 数据 │
└─────────────────────────────────────────┘
三、技术原理深入
3.1 核心技术原理
pymysql 基于 MySQL 原生通信协议 实现,通过 TCP 套接字与 MySQL 服务建立连接,将 Python 代码转换为 MySQL 可识别的 SQL 语句,再将返回结果解析为 Python 数据类型(字典、列表、元组)。
技术一:连接流程原理
- Python 调用
pymysql.connect()发起 TCP 连接请求 - MySQL 服务验证身份(用户名 / 密码)
- 认证通过后建立连接通道,返回连接对象
- 通过连接对象创建游标,执行 SQL 语句
- MySQL 执行 SQL 并返回结果,pymysql 解析结果
- 操作完成后关闭游标与连接,释放资源
技术二:游标工作原理
- 默认游标(Cursor):返回元组格式结果集
- 字典游标(DictCursor):返回字典格式结果集,字段名作为 key,更易用
- 游标执行
execute()发送 SQL,fetchone()/fetchall()获取数据 - 游标占用 MySQL 资源,使用后必须关闭
3.2 数据交互机制
流程一:基础数据交互流程
plaintext
用户调用 → 建立连接 → 创建游标 → 执行 SQL → 获取结果 → 提交/回滚 → 关闭游标 → 关闭连接
流程二:安全参数化查询流程
- 编写带占位符
%s的 SQL 模板(不是 Python 格式化) - 将参数以元组形式传入
execute() - pymysql 自动转义参数,防止 SQL 注入
- 发送安全 SQL 到 MySQL 执行
3.3 性能优化策略
表格
| 优化方向 | 具体方法 | 效果 |
|---|---|---|
| 连接复用 | 使用连接池,避免频繁创建 / 关闭连接 | 提升 50%+ 执行效率 |
| 批量操作 | 使用 executemany() 替代循环 execute() |
减少 80% 网络开销 |
| 结果获取 | 按需 fetchone(),避免全量 fetchall() |
降低内存占用 |
| 事务优化 | 批量操作包裹事务,减少自动提交 | 提升写入速度 |
| 字符集 | 固定使用 utf8mb4,避免编码转换 |
减少报错与性能损耗 |
四、安装与基础配置
4.1 安装 pymysql
bash
运行
bash
# 标准安装(最新稳定版)
pip install pymysql
# 指定版本安装
pip install pymysql==1.1.0
# 国内镜像加速安装
pip install pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple
4.2 安装验证
python
运行
# 验证安装成功
import pymysql
# 打印版本号
print("pymysql 版本:", pymysql.__version__)
输出示例 :pymysql 版本:1.1.0
4.3 MySQL 环境准备
- 启动 MySQL 服务,确保端口
3306开放 - 创建测试数据库:
sql
sql
CREATE DATABASE IF NOT EXISTS test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 创建测试用户(可选):
sql
sql
CREATE USER 'test_user'@'%' IDENTIFIED BY 'Test@123456';
GRANT ALL ON test_db.* TO 'test_user'@'%';
FLUSH PRIVILEGES;
五、基础连接实战(核心代码)
5.1 最基础连接(无异常处理)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
# 数据库连接配置(核心参数)
db_config = {
"host": "127.0.0.1", # 本地地址,远程填服务器IP
"port": 3306, # MySQL默认端口
"user": "root", # 用户名
"password": "你的密码", # 数据库密码
"database": "test_db", # 目标数据库
"charset": "utf8mb4" # 字符集,必须写utf8mb4
}
# 1. 建立数据库连接
conn = pymysql.connect(**db_config)
# 2. 创建游标对象(默认元组游标)
cursor = conn.cursor()
print("✅ 连接成功,游标创建完成")
# 3. 关闭游标
cursor.close()
# 4. 关闭连接
conn.close()
print("✅ 游标与连接已关闭")
5.2 带异常处理的安全连接(生产必备)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
from pymysql import err
# 数据库配置
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 安全连接函数
def safe_mysql_connect():
try:
# 建立连接
conn = pymysql.connect(**db_config)
print("✅ 数据库连接成功")
# 创建游标
cursor = conn.cursor()
print("✅ 游标创建成功")
return conn, cursor
# 捕获连接错误
except err.OperationalError as e:
print(f"❌ 连接失败:用户名/密码错误或服务未启动 → {e}")
return None, None
# 捕获数据库不存在错误
except err.ProgrammingError as e:
print(f"❌ 数据库不存在 → {e}")
return None, None
# 其他未知错误
except Exception as e:
print(f"❌ 未知错误 → {e}")
return None, None
# 调用连接
conn, cursor = safe_mysql_connect()
# 资源释放
if cursor:
cursor.close()
if conn:
conn.close()
print("✅ 资源已释放")
5.3 上下文管理器连接(自动关闭,推荐)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
# 配置
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# with 语句自动管理连接/游标,无需手动关闭
def connect_with_context():
try:
# 建立连接
with pymysql.connect(**db_config) as conn:
print("✅ 连接成功")
# 创建字典游标(返回字典格式,更易用)
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
print("✅ 字典游标创建成功")
return True
except Exception as e:
print(f"❌ 连接失败:{e}")
return False
# 执行
connect_with_context()
5.4 远程 MySQL 连接
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
# 远程数据库配置
remote_db_config = {
"host": "47.xxx.xxx.xxx", # 远程服务器公网IP
"port": 3306,
"user": "remote_user",
"password": "Remote@123",
"database": "test_db",
"charset": "utf8mb4",
"connect_timeout": 5 # 连接超时时间(秒)
}
# 连接远程数据库
def connect_remote_mysql():
try:
conn = pymysql.connect(**remote_db_config)
print("✅ 远程 MySQL 连接成功")
return conn
except Exception as e:
print(f"❌ 远程连接失败:{e}")
return None
# 调用
conn = connect_remote_mysql()
if conn:
conn.close()
六、核心 CURD 操作实战
6.1 创建数据表
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
# 配置
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 创建用户表
def create_user_table():
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
# SQL 语句:创建用户表
create_sql = """
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
password VARCHAR(32) NOT NULL COMMENT '密码',
age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄',
gender ENUM('男','女','未知') DEFAULT '未知' COMMENT '性别',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COMMENT = '用户信息表';
"""
try:
# 执行 SQL
cursor.execute(create_sql)
print("✅ 数据表创建成功")
except Exception as e:
print(f"❌ 创建表失败:{e}")
finally:
# 释放资源
cursor.close()
conn.close()
# 执行创建
create_user_table()
6.2 插入数据(单条 / 批量)
单条插入(参数化,防注入)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 单条插入
def insert_one_user(username, password, age, gender):
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
# 参数化 SQL(%s 是占位符,不是 Python 格式化)
insert_sql = """
INSERT INTO user (username, password, age, gender)
VALUES (%s, %s, %s, %s);
"""
try:
# 执行插入,参数以元组传入
cursor.execute(insert_sql, (username, password, age, gender))
# 提交事务(必须!否则数据不生效)
conn.commit()
print(f"✅ 插入成功,影响行数:{cursor.rowcount}")
except Exception as e:
# 回滚事务
conn.rollback()
print(f"❌ 插入失败:{e}")
finally:
cursor.close()
conn.close()
# 调用
insert_one_user("zhangsan", "123456", 22, "男")
insert_one_user("lisi", "654321", 25, "女")
批量插入(高效)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 批量插入
def insert_many_users(user_list):
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
insert_sql = """
INSERT INTO user (username, password, age, gender)
VALUES (%s, %s, %s, %s);
"""
try:
# 批量执行,效率远高于循环 execute
cursor.executemany(insert_sql, user_list)
conn.commit()
print(f"✅ 批量插入成功,总条数:{cursor.rowcount}")
except Exception as e:
conn.rollback()
print(f"❌ 批量插入失败:{e}")
finally:
cursor.close()
conn.close()
# 测试数据
user_list = [
("wangwu", "111111", 23, "男"),
("zhaoliu", "222222", 24, "女"),
("sunqi", "333333", 21, "未知")
]
# 调用
insert_many_users(user_list)
6.3 查询数据
查询单条数据
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 查询单条
def get_one_user(user_id):
conn = pymysql.connect(**db_config)
# 直接使用字典游标
cursor = conn.cursor(pymysql.cursors.DictCursor)
query_sql = "SELECT * FROM user WHERE id = %s;"
try:
cursor.execute(query_sql, (user_id,))
# 获取一条结果
user = cursor.fetchone()
print("✅ 查询到用户:", user)
return user
except Exception as e:
print(f"❌ 查询失败:{e}")
return None
finally:
cursor.close()
conn.close()
# 调用
get_one_user(1)
查询多条 / 全部数据
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 查询全部用户
def get_all_users():
conn = pymysql.connect(**db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
query_sql = "SELECT id, username, age, gender, create_time FROM user ORDER BY id DESC;"
try:
cursor.execute(query_sql)
# 获取所有结果
user_list = cursor.fetchall()
print(f"✅ 共查询到 {len(user_list)} 条用户")
for user in user_list:
print(user)
return user_list
except Exception as e:
print(f"❌ 查询失败:{e}")
return []
finally:
cursor.close()
conn.close()
# 调用
get_all_users()
6.4 更新数据
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 更新用户年龄
def update_user_age(user_id, new_age):
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
update_sql = "UPDATE user SET age = %s WHERE id = %s;"
try:
cursor.execute(update_sql, (new_age, user_id))
conn.commit()
print(f"✅ 更新成功,影响行数:{cursor.rowcount}")
except Exception as e:
conn.rollback()
print(f"❌ 更新失败:{e}")
finally:
cursor.close()
conn.close()
# 调用
update_user_age(1, 23)
6.5 删除数据
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 删除用户
def delete_user(user_id):
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
delete_sql = "DELETE FROM user WHERE id = %s;"
try:
cursor.execute(delete_sql, (user_id,))
conn.commit()
print(f"✅ 删除成功,影响行数:{cursor.rowcount}")
except Exception as e:
conn.rollback()
print(f"❌ 删除失败:{e}")
finally:
cursor.close()
conn.close()
# 调用
delete_user(5)
七、高级特性实战
7.1 事务管理(保存点)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 带保存点的事务
def transaction_with_savepoint():
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
try:
# 第一步操作
cursor.execute("INSERT INTO user (username, password) VALUES ('test1', '123');")
# 创建保存点
conn.savepoint("sp1")
# 第二步操作
cursor.execute("INSERT INTO user (username, password) VALUES ('test2', '456');")
# 回滚到保存点(撤销第二步,保留第一步)
conn.rollback("sp1")
print("✅ 已回滚到保存点 sp1")
# 提交最终结果
conn.commit()
print("✅ 事务提交完成")
except Exception as e:
conn.rollback()
print(f"❌ 事务失败:{e}")
finally:
cursor.close()
conn.close()
# 调用
transaction_with_savepoint()
7.2 调用存储过程
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
db_config = {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "你的密码",
"database": "test_db",
"charset": "utf8mb4"
}
# 调用存储过程
def call_procedure():
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
try:
# 调用名为 get_user_count 的存储过程
cursor.callproc("get_user_count")
# 获取结果
result = cursor.fetchone()
print("✅ 存储过程执行结果:", result)
conn.commit()
except Exception as e:
print(f"❌ 调用失败:{e}")
finally:
cursor.close()
conn.close()
# 调用
call_procedure()
7.3 连接池使用(高并发必备)
python
运行
python
# -*- coding: utf-8 -*-
import pymysql
from dbutils.pooled_db import PooledDB
# 连接池配置
pool = PooledDB(
creator=pymysql,
maxconnections=10, # 最大连接数
mincached=2, # 初始化空闲连接
maxcached=5, # 最大空闲连接
maxshared=3, # 最大共享连接
blocking=True, # 无连接时阻塞
host="127.0.0.1",
port=3306,
user="root",
password="你的密码",
database="test_db",
charset="utf8mb4"
)
# 从连接池获取连接
def get_conn_from_pool():
conn = pool.connection()
cursor = conn.cursor(pymysql.cursors.DictCursor)
print("✅ 从连接池获取连接成功")
return conn, cursor
# 使用连接池查询
def query_with_pool():
conn, cursor = get_conn_from_pool()
try:
cursor.execute("SELECT COUNT(*) AS count FROM user;")
print("✅ 查询结果:", cursor.fetchone())
finally:
cursor.close()
conn.close() # 归还连接池,不真正关闭
# 调用
query_with_pool()
八、最佳实践分享
8.1 安全最佳实践
- 必用参数化查询,严禁字符串拼接 SQL,彻底杜绝 SQL 注入
- 密码加密存储,使用 MD5/SHA256 加密,不存明文
- 最小权限原则,业务账号仅授予必要权限,不使用 root 运行
- 异常捕获全覆盖,避免程序崩溃与信息泄露
- 关闭自动提交,手动控制事务,保证数据一致性
8.2 性能最佳实践
- 高并发必用连接池,禁止频繁创建 / 关闭连接
- 批量操作必用 executemany,减少网络 IO
- 查询只查需要字段 ,禁止
SELECT * - 大结果集分页查询,避免内存溢出
- 索引优化,查询字段建立索引,提升速度
8.3 代码规范最佳实践
- 配置抽离为常量,不硬编码密码
- 封装通用数据库工具类,复用代码
- 统一异常处理,统一日志输出
- 资源强制释放,使用上下文管理器
- 注释完整,SQL 语句格式化清晰
九、常见问题解答
Q1:报错 Access denied for user 'root'@'localhost'
原因 :用户名 / 密码错误、MySQL 服务未启动、权限不足解决:
- 核对账号密码
- 启动 MySQL 服务
- 授权远程访问:
GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '密码';
Q2:报错 UnicodeEncodeError: 'latin-1' codec can't encode character
原因 :字符集设置错误,未使用 utf8mb4解决 :连接时强制指定 charset="utf8mb4"
Q3:插入数据不生效,无报错
原因 :未执行 conn.commit() 提交事务解决:增删改操作必须手动提交
Q4:远程连接超时
原因 :服务器防火墙未开放 3306 端口、MySQL 绑定本地 IP解决:
- 防火墙放行 3306 端口
- 修改 MySQL 配置
bind-address = 0.0.0.0
Q5:查询结果为 None
原因 :无匹配数据、SQL 错误、游标未正确创建解决:核对 SQL 语句、检查参数、确认数据存在
十、总结与展望
10.1 核心要点回顾
pymysql是 Python 操作 MySQL 的首选纯 Python 库,跨平台、无依赖- 核心流程:建立连接 → 创建游标 → 执行 SQL → 提交 / 回滚 → 关闭资源
- 安全第一:参数化查询 防止 SQL 注入,生产环境禁用字符串拼接
- 性能关键:连接池 + 批量操作 + 事务优化 支撑高并发场景
- 规范编码:异常处理、资源释放、代码封装是项目稳定的基础
10.2 未来发展趋势
pymysql持续兼容 MySQL 8.0+ 新特性,支持更多高级语法- 与 AI 框架结合,实现数据库智能查询、自动化运维
- 异步版本
aiomysql成为高并发 Web 服务主流 - 云原生场景下,pymysql 适配云数据库 RDS 自动连接
10.3 学习建议
- 先练基础:掌握连接、CRUD、异常处理,再学高级特性
- 结合实战:用 Flask/Django 搭建项目,真实场景使用 pymysql
- 深入原理:理解事务、连接池、MySQL 协议,提升排查能力
- 持续跟进:关注 pymysql 版本更新,学习新特性
十一、完整工具类封装(可直接用于项目)
python
运行
python
# -*- coding: utf-8 -*-
"""
pymysql 通用工具类(生产环境可用)
"""
import pymysql
from pymysql import err
from typing import List, Dict, Any, Optional
class PyMySQLUtil:
def __init__(self, host: str, port: int, user: str, password: str, database: str, charset: str = "utf8mb4"):
"""初始化数据库配置"""
self.db_config = {
"host": host,
"port": port,
"user": user,
"password": password,
"database": database,
"charset": charset
}
def __get_conn(self) -> Optional[tuple[pymysql.Connection, pymysql.cursors.DictCursor]]:
"""获取连接和字典游标(私有方法)"""
try:
conn = pymysql.connect(**self.db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
return conn, cursor
except Exception as e:
print(f"❌ 获取连接失败:{e}")
return None
def execute(self, sql: str, params: tuple = None) -> int:
"""执行增删改 SQL,返回影响行数"""
conn, cursor = self.__get_conn()
if not conn or not cursor:
return -1
try:
cursor.execute(sql, params)
conn.commit()
return cursor.rowcount
except Exception as e:
conn.rollback()
print(f"❌ 执行失败:{e}")
return -1
finally:
cursor.close()
conn.close()
def executemany(self, sql: str, params: List[tuple]) -> int:
"""批量执行 SQL"""
conn, cursor = self.__get_conn()
if not conn or not cursor:
return -1
try:
cursor.executemany(sql, params)
conn.commit()
return cursor.rowcount
except Exception as e:
conn.rollback()
print(f"❌ 批量执行失败:{e}")
return -1
finally:
cursor.close()
conn.close()
def fetch_one(self, sql: str, params: tuple = None) -> Optional[Dict[str, Any]]:
"""查询单条数据"""
conn, cursor = self.__get_conn()
if not conn or not cursor:
return None
try:
cursor.execute(sql, params)
return cursor.fetchone()
except Exception as e:
print(f"❌ 查询失败:{e}")
return None
finally:
cursor.close()
conn.close()
def fetch_all(self, sql: str, params: tuple = None) -> List[Dict[str, Any]]:
"""查询多条数据"""
conn, cursor = self.__get_conn()
if not conn or not cursor:
return []
try:
cursor.execute(sql, params)
return cursor.fetchall()
except Exception as e:
print(f"❌ 查询失败:{e}")
return []
finally:
cursor.close()
conn.close()
# 使用示例
if __name__ == "__main__":
# 初始化工具类
db = PyMySQLUtil(
host="127.0.0.1",
port=3306,
user="root",
password="你的密码",
database="test_db"
)
# 查询所有用户
users = db.fetch_all("SELECT id, username FROM user;")
print("所有用户:", users)