Python操作MySQL数据库

目录

一、前言

[二、安装 Python MySQL 连接库](#二、安装 Python MySQL 连接库)

(一)官方推荐库:mysql-connector-python

(二)替代库:PyMySQL

[三、Python 连接 MySQL 数据库](#三、Python 连接 MySQL 数据库)

(一)导入连接库

(二)创建数据库连接

(三)创建游标对象

[(四)执行 SQL 语句](#(四)执行 SQL 语句)

(五)获取查询结果

(六)关闭连接

[四、常见的 MySQL 操作](#四、常见的 MySQL 操作)

(一)插入数据(INSERT)

(二)更新数据(UPDATE)

(三)删除数据(DELETE)

(四)查询数据(SELECT)

[(五)执行多条 SQL 语句](#(五)执行多条 SQL 语句)

[(六)使用 LIKE 进行模糊查询](#(六)使用 LIKE 进行模糊查询)

[(七)使用 JOIN 进行联合查询](#(七)使用 JOIN 进行联合查询)

五、使用连接池

(一)连接池简介

(二)创建连接池

(三)获取连接

(四)连接池的优势

六、事务管理

(一)开始事务

(二)提交事务

(三)回滚事务

(四)事务的隔离级别

(五)事务隔离级别总结

(六)案例

七、数据库连接参数详解

[八、SQL 注入攻击原理与防御](#八、SQL 注入攻击原理与防御)

(一)攻击原理

(二)防御方法

九、游标对象的高级用法

(一)批量操作优化

(二)获取受影67响行数

十、连接池深度解析

(一)核心参数说明

(二)连接池与1011线程安全

十一、事务的原子性与一致性案例

(一)转账场景模拟

(二)事务保证原子性

十二、四种事务隔离级别实战对比

(一)准备测试表

(二)测试场景:两个事务并发执行

(三)不同隔离级别下的结果

(四)隔离级别选择建议

十三、错误处理1220最佳实践

十四、性能优化总结

(一)连接管理层面

[(二)SQL 语句层面](#(二)SQL 语句层面)

(三)事务层面6

十七、文档关键20知识点速查表


一、前言

在现代应用程序中,数据库起着至关重要的作用。MySQL 作为流行的关系型数据库管理系统,被广泛应用于各种规模的应用。在 Python 中,可通过连接库与 MySQL 数据库交互,实现数据增、删、改、查操作。连接池作为优化数据库连接管理的技术,能提高应用性能。本文将介绍如何用 Python 操作 MySQL 数据库,包括建立连接、执行 SQL 语句、事务管理、错误处理等,重点介绍连接池的使用以优化连接效率。

二、安装 Python MySQL 连接库

(一)官方推荐库:mysql-connector-python

命令:pip install mysql-connector-python

(二)替代库:PyMySQL

命令:pip install pymysql

本文以 PyMySQL 为例进行讲解。

三、Python 连接 MySQL 数据库

(一)导入连接库

代码:import pymysql

(二)创建数据库连接

使用pymysql.connect()方法建立连接,需提供 MySQL 服务器地址、用户名、密码和数据库名。

示例代码:

复制代码
db = pymysql.connect(
    host="localhost",  # MySQL数据库地址,通常为localhost或IP地址
    user="root",       # 数据库用户名,通常为root
    password="password",  # 数据库密码
    database="testdb"  # 要连接的数据库名称
)

(三)创建游标对象

建立连接后,创建游标对象以执行 SQL 语句。

代码:cursor = db.cursor()

(四)执行 SQL 语句

通过游标对象的execute()方法执行 SQL 语句,使用%s占位避免 SQL 注入攻击。

示例:cursor.execute("SELECT * FROM users")

(五)获取查询结果

  • fetchall():获取所有结果。

  • fetchone():获取单条记录。
    示例代码:

    results = cursor.fetchall()
    for row in results:
    print(row)

(六)关闭连接

操作完成后,关闭游标和数据库连接。

代码:

复制代码
cursor.close()
db.close()

四、常见的 MySQL 操作

(一)插入数据(INSERT)

使用INSERT INTO语句,通过execute()方法执行,值用%s占位符。

示例代码:

复制代码
cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("Alice", 25))
db.commit()  # 提交事务,保存插入数据

(二)更新数据(UPDATE)

使用UPDATE语句,通过execute()方法执行,添加WHERE条件确保更新特定记录。

示例代码:

复制代码
cursor.execute("UPDATE users SET age = %s WHERE name = %s", (26, "Alice"))
db.commit()  # 提交事务,保存更新数据

(三)删除数据(DELETE)

使用DELETE语句,通过WHERE条件确保删除特定记录。

示例代码:

复制代码
cursor.execute("DELETE FROM users WHERE name = %s", ("Alice",))
db.commit()  # 提交事务,保存删除数据

(四)查询数据(SELECT)

使用SELECT语句,用fetchall()fetchone()获取记录。

示例代码:

复制代码
cursor.execute("SELECT * FROM users")
results = cursor.fetchall()
for row in results:
    print(row)

(五)执行多条 SQL 语句

对于批量插入、更新等操作,使用executemany()方法一次执行多条 SQL 语句。

示例代码:

复制代码
cursor.executemany(
    "INSERT INTO users(name, age) VALUES(%s, %s)",
    [("Bob", 30), ("Charlie", 35), ("David", 28)]
)
db.commit()  # 提交事务

(六)使用 LIKE 进行模糊查询

使用LIKE关键字和%通配符进行模糊查询。

示例代码:

复制代码
cursor.execute("SELECT * FROM users WHERE name LIKE %s", ("%a%",))
results = cursor.fetchall()
for row in results:
    print(row)

(七)使用 JOIN 进行联合查询

使用JOIN关键字合并多个表的数据。

示例代码:

复制代码
cursor.execute(
    "SELECT users.name, orders.amount "
    "FROM users "
    "INNER JOIN orders ON users.id = orders.user_id"
)
results = cursor.fetchall()
for row in results:
    print(row)

五、使用连接池

(一)连接池简介

连接池技术在高并发场景下可提升数据库连接效率。池中提前创建多个数据库连接,客户端从池获取连接,减少连接创建和销毁的开销。

(二)创建连接池

PyMySQL 不直接支持连接池,使用 DBUtils 库创建,需先安装 DBUtils。

命令:pip install dbutils

示例代码:

复制代码
from dbutils.pooled_db import PooledDB
import pymysql

# 数据库连接配置
dbconfig = {
    "host": "localhost",
    "user": "root",
    "password": "password",
    "database": "testdb"
}

# 创建连接池
connection_pool = PooledDB(
    creator=pymysql,  # 使用PyMySQL作为数据库连接库
    maxconnections=5,  # 连接池中最大连接数
    **dbconfig
)

(三)获取连接

从连接池获取连接,使用connection()方法,操作完成后连接自动归还池。

示例代码:

复制代码
db_connection = connection_pool.connection()
cursor = db_connection.cursor()
cursor.execute("SELECT * FROM users")
results = cursor.fetchall()
for row in results:
    print(row)
cursor.close()
db_connection.close()  # 连接自动归还给连接池

(四)连接池的优势

  1. 性能提升:减少创建新连接的开销,提高数据库操作效率。
  2. 资源管理:限制最大连接数,避免数据库过载。
  3. 更易管理:统一管理连接生命周期,简化代码结构。

六、事务管理

事务是由多个 SQL 语句组成的工作单元,保证数据原子性,即所有操作要么都成功,要么都失败。

(一)开始事务

可通过START TRANSACTION显式开启,一般执行 SQL 语句启动事务。

示例:cursor.execute("START TRANSACTION")

(二)提交事务

若事务中所有操作成功,使用commit()方法提交事务,保存更改。

代码:db.commit()

(三)回滚事务

若事务中操作失败,使用rollback()方法回滚事务,撤销更改。

代码:db.rollback()

(四)事务的隔离级别

MySQL 支持四种事务隔离级别,定义了并发事务间的影响,隔离级别越高,干扰越小,性能可能下降,默认隔离级别为REPEATABLE READ

  1. READ UNCOMMITTED(未提交读)
    • 描述:事务可读取其他事务未提交的数据,可能导致 "脏读",隔离性最差。
    • 应用场景:不推荐,除非对数据一致性要求不高。
    • 使用方法cursor.execute("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED")
  2. READ COMMITTED(提交读)
    • 描述:事务只能读取其他事务已提交的数据,避免脏读,可能遇到 "不可重复读",即两次读取数据可能变化(另一事务已提交修改)。
    • 应用场景:适用于大多数常见场景,提供一定隔离性,保证较好性能。
    • 使用方法cursor.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED")
  3. REPEATABLE READ(可重复读)
    • 描述:事务保证在事务内多次读取同一数据时值不变,避免 "不可重复读",但可能出现 "幻读",即读取的数据集在事务执行中变化。
    • 应用场景:需要保证事务数据一致性的场景,如金融系统余额操作等。
    • 使用方法cursor.execute("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ")
  4. SERIALIZABLE(串行化)
    • 描述:最严格的隔离级别,事务像串行一样执行,完全避免脏读、不可重复读和幻读,性能开销最大,可能导致大量锁竞争。
    • 应用场景:对数据一致性要求极高的场景,如库存管理系统、银行转账等。
    • 使用方法cursor.execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE")

(五)事务隔离级别总结

隔离级别 是否允许脏读 是否解决不可重复读 是否解决幻读 性能 应用场景
READ UNCOMMITTED 允许 最好 数据一致性要求不高
READ COMMITTED 较好 大多数常见场景
REPEATABLE READ 一般 数据一致性要求较高场景(默认)
SERIALIZABLE 最差 数据一致性要求极高场景

选择隔离级别时,需根据应用需求平衡数据一致性和性能。数据不频繁冲突时,选较低级别提升性能;数据一致性要求极高时,选较高级别,尽管性能有损失。

(六)案例

复制代码
import pymysql

# 连接到数据库
conn = pymysql.connect(
    host='localhost',
    user='root',
    password='password',
    database='testdb'
)

# 创建游标对象
cursor = conn.cursor()

# 关闭自动提交模式
conn.autocommit = False

try:
    # 开始事务
    # 执行插入操作
    cursor.execute("INSERT INTO users (name, age) VALUES ('Eve', 22)")
    cursor.execute("INSERT INTO orders (user_id, amount) VALUES ((SELECT id FROM users WHERE name = 'Eve'), 120.58)")
    
    # 提交事务
    conn.commit()
    print("事务已提交。")
except pymysql.MySQLError as err:
    # 发生错误,回滚事务
    print(f"错误: {err}")
    conn.rollback()
    print("事务已回滚。")
finally:
    # 关闭游标和连接
    cursor.close()
    conn.close()

七、数据库连接参数详解

在使用pymysql.connect()建立连接时,除基础参数外,还有一些重要配置可优化连接行为:

  • port :指定 MySQL 服务器端口,默认值为3306,示例:port=3307

  • charset :设置连接字符集,避免中文乱码问题,常用值为utf8mb4(支持 Emoji 等特殊字符),示例:charset="utf8mb4"

  • autocomm{insert\_element\_0\_}it :是否开启自动提交模式,默认值为False。若设为True,每次执行 SQL 后会自动提交事务,无需手动调用commit(),但可能降低事务安全性。

  • cursorcl{insert\_element\_1\_}ass :自定义游标类型,如使用pymysql.cursors.DictCursor可返回字典形式结果,便于字段访问:

    复制代码
    cursor = db.cursor(cursorclass=pymysql.cursors.DictCursor)
    results = cursor.fetchall()  # 结果为[{'name': 'Alice', 'age': 25}, ...]

八、SQL 注入攻击原理与防御

(一)攻击原理

通过在 SQL 语句中插入恶意代码,篡改原本逻辑。例如,用户输入"'; DROP TABLE users; --"作为用户名时,若直接拼接 SQL 会导致:

复制代码
# 不安全写法(易受攻击)
username = "恶意输入"
cursor.execute("SELECT * FROM users WHERE name = '" + username + "'")
# 拼接后语句:SELECT * FROM users WHERE name = ''; DROP TABLE users; --'

执行时会先闭合单引号,再执行DROP TABLE删除表,--注释后续内容。

(二)防御方法
  1. 使用占位符%s

    • 所有动态参数通过%s占位,由驱动层自动转义,避免拼接风险。

    • 正确写法

      python

      复制代码
      username = "恶意输入"
      cursor.execute("SELECT * FROM users WHERE name = %s", (username,))  # 自动转义特殊字符
    • 原理:数据库驱动会将%s视为独立参数,与 SQL 语句分离处理,阻断恶意代码注入路径。

  2. 限制输入长度与45格式

    • 对用户输入进行正则校验(如手机号、邮箱格式),拒绝非法字符。
    • 使用框架自带的 ORM(对象关系映射)工具(如 Django ORM),其内部已封装安全的参数传递机制。

九、游标对象的高级用法

(一)批量操作优化

当插入大量数据时,executemany()比循环执行execute()效率更高,减少与数据库的交互次数:

复制代码
# 批量插入1000条数据
data = [("User%d" % i, 18) for i in range(1000)]
cursor.executemany("INSERT INTO users (name, age) VALUES (%s, %s)", data)
db.commit()
  • 优势:仅需一次网络传输即可发送多条语句,适用于 CSV 导入、日志批量写入等场景。
(二)获取受影67响行数

通过cursor.rowcount属性获取最近一次执行 SQL 影响的行数,常用于判断更新 / 删除是否成功:

复制代码
cursor.execute("DELETE FROM users WHERE age < 18")
print(f"删除了{cursor.rowcount}条数据")  # 输出:删除了5条数据

十、连接池深度解析

(一)核心参数说明

在使用DBUtils.PooledDB创建连接池时,可配置以下参数优化性能:

  • mincached :连接池中初始化的空闲连接数,默认值为0。若设为2,启动时会创建 2 个空闲连接等待使用,减少首次请求的连接创建延迟。
  • maxcached :连接池中最多可保持的空闲连接数,默认值为0(不限制)。若设为5,当空闲连接超过 5 个时,会自动关闭多余连接,释放资源。
  • maxusage :单个连接的最大使用次数,默认值为0(不限制)。达到次数后,连接会被强制关闭并重新创建,避免长时间使用导致的连接泄漏。
(二)连接池与1011线程安全
  • PooledDB基于线程本地存储(Thread Local Storage)实现,每个线程获取的连接独立,不会出现线程间连接混用的问题。

  • 示例:多线程环境下安全使用连接池:

    复制代码
    import threading
    from dbutils.pooled_db import PooledDB
    import pymysql
    
    pool = PooledDB(creator=pymysql, maxconnections=10, ...)
    
    def query_data():
        conn = pool.connection()
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM users")
        result = cursor.fetchone()
        conn.close()  # 连接归还池中,自动释放给其他线程
        print(f"用户数:{result[0]}")
    
    # 启动10个线程并发查询
    threads = [threading.Thread(target=query_data) for _ in range(10)]
    for t in threads: t.start()
    for t in threads: t.join()

十一、事务的原子性与一致性案例

(一)转账场景模拟

假设用户 A 向用户 B 转账 100 元,需执行以下步骤:

  1. 扣除用户 A 的余额(UPDATE accounts SET balance = balance - 100 WHERE name = 'A')。
  2. 增加用户 B 的余额(UPDATE accounts SET balance = balance + 100 WHERE name = 'B')。
(二)事务保证原子性

若步骤 1 执行成功后系统崩溃,未执行步骤 2,事务未提交时,步骤 1 的修改会被回滚,确保数据不丢失、不脏写:

复制代码
try:
    conn.autocommit = False  # 关闭自动提交,开启事务
    # 扣除A的余额
    cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE name = 'A'")
    # 模拟系统崩溃(抛出异常)
    raise Exception("系统错误")
    # 增加B的余额(未执行)
    cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE name = 'B'")
    conn.commit()  # 不会执行到这里
except:
    conn.rollback()  # 回滚,A的余额恢复原状
finally:
    conn.close()

十二、四种事务隔离级别实战对比

(一)准备测试表
复制代码
CREATE TABLE test_transaction (
    id INT PRIMARY KEY AUTO_INCREMENT,
    value INT
);
INSERT INTO test_transaction (value) VALUES (100);
(二)测试场景:两个事务并发执行
事务 1(会话 1) 事务 2(会话 2)
START TRANSACTION; START TRANSACTION;
SELECT value FROM test_transaction WHERE id = 1;(读取值为 100) UPDATE test_transaction SET value = 200 WHERE id = 1;
-- 等待事务2执行操作 -- COMMIT;
SELECT value FROM test_transaction WHERE id = 1; -- 无操作 --
(三)不同隔离级别下的结果
  1. READ UNCOMMITTED
    • 事务 1 第二次读取值为 200(读取到事务 2 未提交的修改,脏读)。
  2. READ COMMITTED
    • 事务 1 第二次读取值为 200(事务 2 已提交,可重复读不成立,出现不可重复读)。
  3. REPEATABLE READ (MySQL 默认):
    • 事务 1 第二次读取值仍为 100(通过 MVCC 机制实现可重复读,避免不可重复读)。
  4. SERIALIZABLE
    • 事务 2 的UPDATE会被阻塞,直到事务 1 提交或回滚,最终事务 1 读取值为 200(串行执行,无幻读)。
(四)隔离级别选择建议
  • 互联网应用 :通常使用READ COMMITTED(如 Oracle 默认级别),在保证一致性的同时提供较高并发性能。
  • 金融交易系统 :选择REPEATABLE READSERIALIZABLE,确保资金操作的严格一致性,宁可牺牲部分性能。

十三、错误处理1220最佳实践

在数据库操作中,需捕获常见异常并处理,避免程序崩溃:

复制代码
try:
    # 执行可能出错的SQL
    cursor.execute("INSERT INTO users (name) VALUES (%s)", ("Alice",))
    db.commit()
except pymysql.MySQLError as err:
    # 捕获数据库异常
    error_code = err.args[0]
    error_msg = err.args[1]
    if error_code == 1062:  # 唯一键冲突(Duplicate entry)
        print(f"错误:重复数据,原因:{error_msg}")
    elif error_code == 1045:  # 权限拒绝(Access denied)
        print("错误:数据库连接权限不足")
    else:
        print(f"未知错误:{error_msg}")
    db.rollback()  # 回滚事务
finally:
    # 确保资源释放
    if 'cursor' in locals() and not cursor.closed:
        cursor.close()
    if 'db' in locals() and db.open:
        db.close()
  • 常见错误码:
    • 1062:唯一键冲突(如重复插入相同用户名)。
    • 1451:外键约束冲突(删除主表数据前未删除子表相关记录)。
    • 2003:无法连接数据库(服务器地址错误或端口被防火墙阻断)。

十四、性能优化总结

(一)连接管理层面
  • 使用连接池替代每次请求创建新连接,减少 TCP 握手和认证开销。
  • 合理设置连接池max{insert\_element\_6\_}connections参数,避免超过 MySQL 服务器的max_connections限制(可通过SHOW VARIABLES LIKE 'max_connections'查看)。
(二)SQL 语句层面
  • 对高频查询字段添加索引,避免全表扫描(如CREATE INDEX idx_name ON users(name))。
  • 避免使用SELECT *,只查询需要的字段,减少数据传输量。
  • 批量操作时使用executemany()而非循环execute(),提升插入 / 更新效率。
(三)事务层面6
  • 尽量缩短事务范围,将非必要操作移出事务块,减少锁持有时间。
  • 对读多写少的场景,可降低隔离级别(如使用READ COMMITTED)以提升并发度。

十七、文档关键20知识点速查表

知识点 核心内容 文档对应段落
连接 MySQL pymysql.connect()参数:host、user、password、database
执行 SQL c{insert\_element\_9\_}ursor.execute()用于单条语句,executemany()用于批量操作
事务管理 co{insert\_element\_10\_}mmit()提交,rollback()回滚,默认隔离级别REPEATABLE READ
连接池 使用D{insert\_element\_11\_}BUtils.PooledDB创建,参数maxconnections控制最大连接数
隔离级别 四种级911别:READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE
相关推荐
miaoyumeng_wn3 分钟前
5月21日学习笔记
笔记·学习·oracle
五步晦暝5 分钟前
【Excel 支持正则的方法】解决VBA引入正则的方法和步骤
数据库·mysql·excel
卡戎-caryon9 分钟前
【MySQL】07.表内容的操作
linux·网络·数据库·mysql·存储引擎
一只fish29 分钟前
MySQL 8.0 OCP 1Z0-908 题目解析(11)
数据库·mysql
麓殇⊙36 分钟前
黑马点评--基于Redis实现共享session登录
数据库·redis·firefox
zhutoutoutousan1 小时前
解决 Supabase “permission denied for table XXX“ 错误
javascript·数据库·oracle·个人开发
泽韦德1 小时前
【MySQL】第8节|Innodb底层原理与Mysql日志机制深入剖析(一)
数据库·mysql
vvilkim1 小时前
MongoDB 数据库迁移:完整指南与最佳实践
数据库·mongodb
vvilkim1 小时前
MongoDB索引:原理、实践与优化指南
数据库·mongodb
卑微的Coder1 小时前
Redis 常用命令
数据库·redis·缓存