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}")
 

九、常见问题与解决

  1. 中文乱码
    连接时指定 charset="utf8mb4",并确保数据库表的字符集为 utf8mb4utf8mb4 支持所有 Unicode 字符,包括 emoji,而 utf8 仅支持部分)。
  2. 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';
      
       
  3. 连接超时
    长时间未操作导致连接被数据库关闭,可在连接参数中添加 ping=True(获取连接时自动检测并重建连接):
    conn = pymysql.connect(..., ping=True)
    
     
  4. 游标关闭
    游标使用后建议关闭(cursor.close()),释放资源。

十、PyMySQL 与 mysql-connector 对比

特性PyMySQLmysql-connector(官方)
实现方式 纯 Python C 扩展 + Python
安装难度 简单(pip 直接安装) 可能需要依赖系统库
性能 略低(纯 Python 实现) 略高(C 扩展加速)
兼容性 兼容 MySQL 5.5+、MariaDB 完全兼容 MySQL 官方特性
流行度 更高(Python 社区更常用) 官方维护,稳定性有保障

posted on 2025-08-21 09:12  小陶coding  阅读(381)  评论(0)    收藏  举报