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

Django 1.11.49中原生SQL与模型查询的单事务读取问题

问题解决:并发场景下跨表查询的数据一致性问题

问题原因

你的核心问题出在数据库事务隔离级别和查询的一致性快照上:

  1. 默认数据库隔离级别为「读已提交」,即使在同一个事务内,后续查询会读取到其他已提交事务的最新数据。
  2. API先通过原生SQL读取Table A的旧数据,此时后台事务完成了A、B表的删改并提交,后续用旧外键查询Table B时,旧的B记录已被删除,自然无结果。
  3. 之前仅用transaction.atomic()包裹查询无效,是因为没有调整隔离级别,事务内的查询仍会看到外部提交的修改。

解决方案

要让两次查询共享同一数据快照,不受后台更新影响,需要将事务隔离级别设置为「可重复读」,并确保原生SQL与Django ORM使用同一个事务连接。

方案1:原生SQL+ORM结合(保留原生查询)

from django.db import transaction, connection

with transaction.atomic():
    # 设置事务隔离级别为可重复读(适配PostgreSQL/MySQL等主流数据库)
    with connection.cursor() as cursor:
        cursor.execute("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;")
        
        # 原生SQL查询Table A
        query = "SELECT * FROM A WHERE status = 1;"
        cursor.execute(query)
        results = cursor.fetchall()
    
    list_of_values = get_values_for_table_B(results)
    # ORM查询Table B,自动复用当前事务的连接和数据快照
    b_records = list(B.objects.filter(values__in=list_of_values))

方案2:全ORM查询(更简洁,推荐)

如果可以替换原生SQL为Django ORM,代码会更简洁,且事务一致性更易维护:

from django.db import transaction

with transaction.atomic():
    # 设置可重复读隔离级别
    transaction.set_autocommit(False)
    try:
        # ORM查询Table A的活跃数据
        a_records = A.objects.filter(status=1)
        list_of_values = get_values_for_table_B(a_records.values())
        
        # 基于同一快照查询Table B
        b_records = list(B.objects.filter(values__in=list_of_values))
    finally:
        transaction.set_autocommit(True)

关键说明

  • 「可重复读」隔离级别会让事务内的所有查询都基于事务启动时的数据快照,不会看到其他事务在事务期间提交的修改,完美解决你的并发一致性问题。
  • 后台进程的transaction.atomic()用法是正确的,原子性删改A、B表不会破坏数据关联。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:45:36