核心步骤
使用 PyMySQL 删除数据的步骤与插入、查询等操作基本一致:

- 安装 PyMySQL: 如果尚未安装,请先安装。
- 建立数据库连接: 使用
pymysql.connect()创建一个连接对象。 - 创建游标: 通过连接对象创建一个游标(
cursor),游标用于执行 SQL 语句。 - 执行 DELETE 语句: 使用游标的
execute()方法来执行你的 SQLDELETE语句。 - 提交事务: 非常重要! 删除、插入、更新操作需要手动提交 (
commit) 才能真正生效。 - 关闭游标和连接: 操作完成后,关闭游标和连接以释放资源。
基本删除操作(有 SQL 注入风险)
我们先来看一个最简单的例子,这个例子不推荐在生产环境中使用,因为它存在巨大的安全漏洞。
假设我们有一个 students 表,结构如下:
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT
);
示例代码 (不推荐):
import pymysql
# 1. 建立连接
# 请替换成你自己的数据库信息
connection = pymysql.connect(
host='localhost',
user='your_username',
password='your_password',
database='your_database'
)
try:
# 2. 创建游标
with connection.cursor() as cursor:
# 3. 准备 SQL 语句 (不推荐的方式,直接拼接字符串)
student_id_to_delete = 101
sql = f"DELETE FROM students WHERE id = {student_id_to_delete}"
# 4. 执行 SQL 语句
affected_rows = cursor.execute(sql)
# 5. 提交事务
connection.commit()
print(f"成功删除了 {affected_rows} 行数据。")
finally:
# 6. 关闭连接
connection.close()
为什么不推荐?
student_id_to_delete 的值来自用户输入,101; DROP TABLE students; --,那么最终的 SQL 语句会变成:
DELETE FROM students WHERE id = 101; DROP TABLE students; --
这会先删除 id 为 101 的学生,然后执行 DROP TABLE students 删除整个表,造成灾难性后果,这就是 SQL 注入。
安全的删除操作(使用参数化查询)
为了防止 SQL 注入,我们必须使用 参数化查询(也称为预处理语句),PyMySQL 通过 cursor.execute() 的第二个参数(一个元组或字典)来实现。
这是标准且必须的做法。
使用元组 (适用于 WHERE 子句中的简单条件)
import pymysql
# 1. 建立连接
connection = pymysql.connect(
host='localhost',
user='your_username',
password='your_password',
database='your_database'
)
try:
# 2. 创建游标
with connection.cursor() as cursor:
# 3. 定义 SQL 语句,使用 %s 作为占位符
# 注意:即使 %s 代表数字,也必须用引号括起来,PyMySQL 会自动处理
sql = "DELETE FROM students WHERE id = %s"
# 4. 定义要删除的 ID,放在一个元组中
student_id_to_delete = (101,) # 元组中只有一个元素时,末尾必须有逗号
# 5. 执行 SQL 语句,将参数传入
affected_rows = cursor.execute(sql, student_id_to_delete)
# 6. 提交事务
connection.commit()
print(f"成功删除了 {affected_rows} 行数据。")
finally:
# 7. 关闭连接
connection.close()
关键点:
- SQL 语句中的值部分用
%s作为占位符。 - 参数必须放在一个 元组 中,如果只有一个参数,记得在末尾加逗号,如
(101,),否则它会被解释为一个整数而不是元组。
使用字典 (适用于多个或命名参数)
当你的 DELETE 语句有多个条件时,使用字典会更加清晰和灵活。
import pymysql
# 1. 建立连接
connection = pymysql.connect(
host='localhost',
user='your_username',
password='your_password',
database='your_database'
)
try:
# 2. 创建游标
with connection.cursor() as cursor:
# 3. 定义 SQL 语句,使用 %(key)s 作为占位符
sql = "DELETE FROM students WHERE name = %(name)s AND age > %(age)s"
# 4. 定义参数,放在一个字典中
delete_params = {
'name': 'Tom',
'age': 20
}
# 5. 执行 SQL 语句,将字典传入
affected_rows = cursor.execute(sql, delete_params)
# 6. 提交事务
connection.commit()
print(f"成功删除了 {affected_rows} 行数据。")
finally:
# 7. 关闭连接
connection.close()
关键点:
- SQL 语句中的占位符是
%(key)s的形式,key对应字典中的键。 - 参数放在一个 字典 中,代码可读性更高。
删除所有数据(TRUNCATE vs DELETE)
有时候你可能需要清空一张表,有两种方法:
DELETE FROM table_name;
- 作用:删除表中的所有行。
- 特点:
- 逐行删除,速度较慢,尤其是在大表上。
- 每删除一行,都会在事务日志中记录。
- 不会重置自增主键 (AUTO_INCREMENT),如果原最大 ID 是 1000,下次插入新记录时,ID 会从 1001 开始。
- 可以配合
WHERE子句,有条件地删除。
TRUNCATE TABLE table_name;
- 作用:快速清空表。
- 特点:
- 速度非常快,因为它直接删除并重建表,而不是逐行删除。
- 不会记录在事务日志中(或记录非常少),因此通常无法回滚。
- 会重置自增主键 (AUTO_INCREMENT),如果原最大 ID 是 1000,下次插入新记录时,ID 会从 1 开始。
- 不能有
WHERE子句,只能清空整个表。
如何选择?
- 如果只是想快速清空表,并且希望 ID 从 1 重新开始,使用
TRUNCATE。 - 如果需要在清空前进行一些复杂的条件判断,或者需要保留自增 ID 的历史最大值,使用
DELETE。
使用 PyMySQL 执行 TRUNCATE:
import pymysql
connection = pymysql.connect(
host='localhost',
user='your_username',
password='your_password',
database='your_database'
)
try:
with connection.cursor() as cursor:
# 使用 TRUNCATE 语句
sql = "TRUNCATE TABLE students"
# TRUNCATE 不需要参数,execute() 只传 SQL 语句
cursor.execute(sql)
# 提交事务
connection.commit()
print("students 表已成功清空。")
finally:
connection.close()
完整的最佳实践示例
这是一个结合了错误处理和上下文管理器的完整、健壮的示例。
import pymysql
from pymysql import MySQLError
# 数据库配置
db_config = {
'host': 'localhost',
'user': 'your_username',
'password': 'your_password',
'database': 'your_database',
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor # 使用字典游标,结果更易读
}
def delete_student_by_id(student_id):
"""
根据ID安全地删除一个学生记录。
"""
# 使用 'with' 语句管理连接,它会自动处理连接的关闭
try:
with pymysql.connect(**db_config) as connection:
with connection.cursor() as cursor:
# 1. 定义安全的 SQL 语句和参数
sql = "DELETE FROM students WHERE id = %s"
params = (student_id,)
# 2. 执行删除
affected_rows = cursor.execute(sql, params)
# 3. 提交事务
connection.commit()
if affected_rows > 0:
print(f"成功删除 ID 为 {student_id} 的学生。")
return True
else:
print(f"未找到 ID 为 {student_id} 的学生,未执行删除。")
return False
except MySQLError as e:
# 如果发生错误,回滚事务(虽然 with 语句在异常时也会回滚,但显式写出来更清晰)
print(f"数据库操作失败: {e}")
if 'connection' in locals() and connection.open:
connection.rollback()
return False
# --- 调用函数 ---
delete_student_by_id(102)
delete_student_by_id(999) # 这个ID不存在,会打印未找到的提示
| 操作 | 关键点 | 示例 |
|---|---|---|
| 基本删除 | 直接拼接 SQL,有 SQL 注入风险,不要使用。 | sql = f"DELETE ... WHERE id = {id}" |
| 安全删除 | 必须使用参数化查询,用 %s 作占位符,参数放在元组或字典中。 |
sql = "DELETE ... WHERE id = %s"cursor.execute(sql, (101,)) |
| 清空表 | DELETE 保留自增 ID,慢;TRUNCATE 重置自增 ID,快。 |
cursor.execute("TRUNCATE TABLE students") |
| 事务 | INSERT, UPDATE, DELETE 必须调用 connection.commit() 才生效。 |
connection.commit() |
| 资源管理 | 使用 with 语句管理连接和游标,确保它们被正确关闭。 |
with pymysql.connect(...) as conn: |
| 错误处理 | 使用 try...except 捕获数据库异常,并在出错时回滚。 |
except MySQLError as e: |
