You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django项目中获取MySQL更新查询受影响行数的方法

解决Django操作远程MySQL数据库时获取更新受影响行数的问题

核心解决方案:使用cursor的rowcount属性替代execute()返回值

UPDATE/DELETE这类写操作不会返回结果集,所以fetchone()/fetchall()返回None是正常行为。而Django封装的cursor.execute()返回值并不等同于受影响行数,正确的做法是直接读取cursor.rowcount属性——这是符合Python DB API 2.0规范的标准方式,pymysql驱动完全支持。

具体实现步骤

  1. 配置远程数据库
    在Django的settings.py中添加远程数据库的配置:
DATABASES = {
    'default': {
        # 本地Django数据库配置
    },
    'remote_db': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'remote_database_name',
        'USER': 'remote_db_user',
        'PASSWORD': 'remote_db_password',
        'HOST': 'remote_host_ip_or_domain',
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8mb4',
            # 可选:开启自动提交避免手动commit
            'autocommit': True,
        },
    }
}
  1. Celery任务中执行更新并获取受影响行数
from celery import shared_task
from django.db import connections

@shared_task
def update_remote_record(record_id, new_value):
    try:
        # 获取远程数据库连接的cursor
        with connections['remote_db'].cursor() as cursor:
            update_sql = "UPDATE your_target_table SET your_column = %s WHERE id = %s"
            # 执行更新语句(参数化查询避免SQL注入)
            cursor.execute(update_sql, (new_value, record_id))
            
            # 获取实际受影响的行数
            affected_rows = cursor.rowcount
            
            # 如果未开启autocommit,必须手动提交事务
            if not connections['remote_db'].get_autocommit():
                connections['remote_db'].commit()
            
            # 根据受影响行数判断结果
            if affected_rows == 0:
                # 无匹配数据或未修改,执行补救逻辑
                # 示例:记录日志、重试任务、触发告警等
                log_update_failure(record_id)
                raise ValueError(f"No record found or updated for ID: {record_id}")
            return f"Successfully updated {affected_rows} row(s)"
    except Exception as e:
        # 异常时回滚事务
        if not connections['remote_db'].get_autocommit():
            connections['remote_db'].rollback()
        # 处理异常逻辑
        handle_task_exception(e)

关键说明

  • 为什么之前的方法无效?
    • fetchone()/fetchall()仅适用于SELECT这类返回结果集的查询,写操作本身不会返回数据,所以返回None是正常的。
    • Django对数据库cursor做了封装,execute()的返回值并非pymysql原生的受影响行数,而rowcount属性才是驱动提供的标准字段,能准确返回被修改/删除的行数。
  • 避免先SELECT再UPDATE的方案:这种做法存在竞态条件(SELECT后到UPDATE前,数据可能被其他进程修改),直接通过rowcount判断更可靠。
  • 事务注意事项:如果未开启autocommit,必须手动执行commit(),否则修改不会持久化到数据库,即使rowcount显示有数值也无效。

内容的提问来源于stack exchange,提问作者Abpostman1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:03:39