杰瑞科技汇

Python pymysql如何正确执行删除操作?

核心步骤

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

Python pymysql如何正确执行删除操作?-图1
(图片来源网络,侵删)
  1. 安装 PyMySQL: 如果尚未安装,请先安装。
  2. 建立数据库连接: 使用 pymysql.connect() 创建一个连接对象。
  3. 创建游标: 通过连接对象创建一个游标(cursor),游标用于执行 SQL 语句。
  4. 执行 DELETE 语句: 使用游标的 execute() 方法来执行你的 SQL DELETE 语句。
  5. 提交事务: 非常重要! 删除、插入、更新操作需要手动提交 (commit) 才能真正生效。
  6. 关闭游标和连接: 操作完成后,关闭游标和连接以释放资源。

基本删除操作(有 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:
分享:
扫描分享到社交APP
上一篇
下一篇