Python3 MySQL 数据库连接 - PyMySQL 驱动详解
PyMySQL 是一个纯 Python 实现的 MySQL 客户端库,兼容 Python DB API 2.0 规范,常用于在 Python3 中连接和操作 MySQL 或 MariaDB 数据库。相比官方的
mysql-connector,PyMySQL 安装简单、性能稳定,是 Python 操作 MySQL 的主流选择之一。本文详细讲解其使用方法。
一、安装 PyMySQL
通过
pip 安装 PyMySQL(支持 Python3.6+):pip install pymysql
验证安装:
import pymysql
print(pymysql.__version__) # 输出版本号,如 1.1.0
二、连接数据库
使用
pymysql.connect() 方法创建数据库连接,需指定必要的连接参数。基本连接示例:
import pymysql
# 连接配置
config = {
"host": "localhost", # 数据库主机地址(默认localhost)
"user": "root", # 用户名
"password": "your_password", # 密码
"database": "test_db", # 要连接的数据库(可选)
"port": 3306, # 端口(默认3306)
"charset": "utf8mb4", # 字符集(支持中文和emoji)
"cursorclass": pymysql.cursors.DictCursor # 游标类型(可选,默认返回元组)
}
try:
# 建立连接
conn = pymysql.connect(**config)
print("数据库连接成功!")
except pymysql.MySQLError as e:
print(f"连接失败:{e}")
finally:
# 关闭连接(重要!)
if 'conn' in locals() and conn.open:
conn.close()
print("连接已关闭")
核心连接参数说明:
| 参数名 | 说明 | 默认值 |
|---|---|---|
host |
数据库主机地址 | localhost |
user |
登录用户名 | 无 |
password |
登录密码 | 无 |
database |
连接后默认使用的数据库 | 无 |
port |
端口号 | 3306 |
charset |
字符编码(推荐 utf8mb4) |
utf8 |
cursorclass |
游标类型(DictCursor 返回字典) |
Cursor(返回元组) |
autocommit |
是否自动提交事务(True/False) |
False |
connect_timeout |
连接超时时间(秒) | 10 |
三、执行 SQL 语句(CRUD 操作)
连接成功后,通过游标(cursor) 执行 SQL 语句。游标是操作数据库的核心对象,用于发送 SQL 命令和获取结果。
1. 创建游标
# 从连接对象获取游标(若连接时已指定cursorclass,此处无需重复设置)
cursor = conn.cursor()
# 若需返回字典类型结果(键为列名),可单独指定:
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
2. 查询操作(SELECT)
使用
cursor.execute() 执行查询,通过 fetchone()(单条)、fetchall()(全部)或 fetchmany(size)(指定条数)获取结果。示例:查询
users 表try:
# SQL 查询语句(使用%s作为占位符)
sql = "SELECT id, name, age FROM users WHERE age > %s"
# 执行查询(参数以元组传入,防SQL注入)
cursor.execute(sql, (18,))
# 获取单条结果
# row = cursor.fetchone()
# print(row) # 若为DictCursor,输出:{'id': 1, 'name': '张三', 'age': 20}
# 获取所有结果
rows = cursor.fetchall()
for row in rows:
print(f"ID: {row['id']}, 姓名: {row['name']}, 年龄: {row['age']}")
except pymysql.MySQLError as e:
print(f"查询失败:{e}")
3. 插入操作(INSERT)
插入数据需调用
conn.commit() 提交事务(默认 autocommit=False),可通过 cursor.lastrowid 获取自增 ID。示例:插入单条数据
try:
sql = "INSERT INTO users (name, age, email) VALUES (%s, %s, %s)"
# 插入参数
data = ("张三", 25, "zhangsan@example.com")
# 执行插入
cursor.execute(sql, data)
# 提交事务(必须!否则数据不生效)
conn.commit()
print(f"插入成功,自增ID:{cursor.lastrowid}")
except pymysql.MySQLError as e:
# 出错时回滚
conn.rollback()
print(f"插入失败:{e}")
4. 更新操作(UPDATE)
更新操作需提交事务,通过
cursor.rowcount 获取影响的行数。示例:更新数据
try:
sql = "UPDATE users SET age = %s WHERE name = %s"
data = (26, "张三") # 将"张三"的年龄改为26
cursor.execute(sql, data)
conn.commit()
print(f"更新成功,影响行数:{cursor.rowcount}")
except pymysql.MySQLError as e:
conn.rollback()
print(f"更新失败:{e}")
5. 删除操作(DELETE)
删除操作同样需要提交事务。
示例:删除数据
try:
sql = "DELETE FROM users WHERE id = %s"
data = (1,) # 删除ID为1的记录
cursor.execute(sql, data)
conn.commit()
print(f"删除成功,影响行数:{cursor.rowcount}")
except pymysql.MySQLError as e:
conn.rollback()
print(f"删除失败:{e}")
四、参数化查询(防 SQL 注入)
严禁使用字符串拼接构造 SQL,必须使用
%s 作为占位符(注意:PyMySQL 仅支持 %s,不支持 ? 或其他符号),参数通过 execute() 方法传入。错误示例(危险,存在注入风险):
# 错误:字符串拼接导致SQL注入
name = "张三' OR '1'='1" # 恶意输入
sql = f"SELECT * FROM users WHERE name = '{name}'" # 拼接后会查询所有数据
正确示例(安全):
# 正确:使用%s占位符
name = "张三' OR '1'='1"
sql = "SELECT * FROM users WHERE name = %s"
cursor.execute(sql, (name,)) # 参数以元组传入,驱动自动转义
五、事务处理
PyMySQL 默认关闭自动提交(
autocommit=False),事务需手动提交。事务确保多步操作 “要么全部成功,要么全部失败”(如转账场景)。示例:事务处理
try:
# 步骤1:扣减A账户余额
sql1 = "UPDATE accounts SET balance = balance - 100 WHERE id = 1"
cursor.execute(sql1)
# 步骤2:增加B账户余额
sql2 = "UPDATE accounts SET balance = balance + 100 WHERE id = 2"
cursor.execute(sql2)
# 全部成功,提交事务
conn.commit()
print("转账成功")
except pymysql.MySQLError as e:
# 任何一步失败,回滚所有操作
conn.rollback()
print(f"转账失败,已回滚:{e}")
开启自动提交(不推荐,除非特殊场景):
conn.autocommit(True) # 所有操作立即生效,无需手动commit
六、异常处理
PyMySQL 定义了多种异常,继承自
pymysql.MySQLError,常用异常类:| 异常类 | 说明 |
|---|---|
OperationalError |
连接相关错误(如连接失败、超时) |
ProgrammingError |
SQL 语法错误、表不存在等程序错误 |
IntegrityError |
数据完整性错误(如主键冲突、外键约束) |
DataError |
数据格式错误(如类型不匹配) |
示例:捕获异常
try:
# 数据库操作
cursor.execute("SELECT * FROM non_existent_table")
except pymysql.ProgrammingError as e:
print(f"SQL错误:{e}") # 表不存在时触发
except pymysql.OperationalError as e:
print(f"连接错误:{e}")
except pymysql.MySQLError as e:
print(f"数据库错误:{e}")
except Exception as e:
print(f"未知错误:{e}")
七、连接池(提升性能)
高频访问场景(如 Web 应用)中,频繁创建 / 关闭连接会消耗资源。可通过
DBUtils 库实现连接池(PyMySQL 本身无内置连接池)。安装 DBUtils:
pip install dbutils
使用连接池示例:
from dbutils.pooled_db import PooledDB
import pymysql
# 连接池配置
pool_config = {
"host": "localhost",
"user": "root",
"password": "your_password",
"database": "test_db",
"charset": "utf8mb4",
"cursorclass": pymysql.cursors.DictCursor,
"maxconnections": 10, # 最大连接数
"mincached": 2, # 初始化时连接池中的连接数
"maxcached": 5, # 连接池中空闲连接的最大数量
"blocking": True # 无可用连接时是否阻塞等待(True:等待,False:报错)
}
# 创建连接池
pool = PooledDB(pymysql,** pool_config)
# 从连接池获取连接
conn = pool.connection()
cursor = conn.cursor()
# 执行操作(与普通连接一致)
cursor.execute("SELECT 1")
print(cursor.fetchone()) # 输出:{'1': 1}
# 归还连接到池(无需关闭,关闭会放回池)
conn.close()
八、批量操作(提升效率)
对于批量插入 / 更新,使用
cursor.executemany() 比多次调用 execute() 更高效(减少网络交互)。示例:批量插入
try:
sql = "INSERT INTO users (name, age) VALUES (%s, %s)"
# 批量数据(列表中的元组对应每条记录)
data = [("李四", 22), ("王五", 30), ("赵六", 27)]
# 批量执行
cursor.executemany(sql, data)
conn.commit()
print(f"批量插入成功,共插入 {cursor.rowcount} 条记录")
except pymysql.MySQLError as e:
conn.rollback()
print(f"批量插入失败:{e}")
九、常见问题与解决
-
中文乱码
连接时指定charset="utf8mb4",并确保数据库表的字符集为utf8mb4(utf8mb4支持所有 Unicode 字符,包括 emoji,而utf8仅支持部分)。 -
MySQL 8.0 认证错误
MySQL 8.0 默认使用caching_sha2_password认证插件,PyMySQL 旧版本可能不支持。解决方法:- 升级 PyMySQL 到 1.0.2+ 版本;
- 或修改用户认证方式为
mysql_native_password:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';
-
连接超时
长时间未操作导致连接被数据库关闭,可在连接参数中添加ping=True(获取连接时自动检测并重建连接):conn = pymysql.connect(..., ping=True) -
游标关闭
游标使用后建议关闭(cursor.close()),释放资源。
十、PyMySQL 与 mysql-connector 对比
| 特性 | PyMySQL | mysql-connector(官方) |
|---|---|---|
| 实现方式 | 纯 Python | C 扩展 + Python |
| 安装难度 | 简单(pip 直接安装) | 可能需要依赖系统库 |
| 性能 | 略低(纯 Python 实现) | 略高(C 扩展加速) |
| 兼容性 | 兼容 MySQL 5.5+、MariaDB | 完全兼容 MySQL 官方特性 |
| 流行度 | 更高(Python 社区更常用) | 官方维护,稳定性有保障 |
浙公网安备 33010602011771号