Django项目中获取MySQL更新查询受影响行数的方法
解决Django操作远程MySQL数据库时获取更新受影响行数的问题
核心解决方案:使用cursor的rowcount属性替代execute()返回值
UPDATE/DELETE这类写操作不会返回结果集,所以fetchone()/fetchall()返回None是正常行为。而Django封装的cursor.execute()返回值并不等同于受影响行数,正确的做法是直接读取cursor.rowcount属性——这是符合Python DB API 2.0规范的标准方式,pymysql驱动完全支持。
具体实现步骤
- 配置远程数据库
在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, }, } }
- 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
相关产品推荐
相关产品推荐

