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

使用MS SQL时Django事务失效问题求助

解决Django 1.11.8 + MS SQL事务失效&导入缓慢问题

我之前在维护旧版Django项目时,也碰到过和你一模一样的问题——SQLite下事务跑的好好的,切到MS SQL就没了事务日志,导入速度暴跌还没法回滚。结合你的场景,我来拆解下问题原因和解决办法:

为什么SQLite正常,MS SQL掉链子?

SQLite的Django驱动在transaction.atomic()块里会自动关掉自动提交,老老实实走显式事务;但Django 1.11.x搭配sql_server.pyodbc驱动时,默认的数据库配置是开启AUTOCOMMIT的,而且transaction.atomic(using='mssql')在旧版里偶尔会出现连接绑定失效的情况,导致每一次save()都自动提交成独立事务——这就是你看不到BEGIN日志、速度慢5倍、异常没法回滚的根本原因。

一步步解决问题

1. 先把数据库配置的自动提交关了

修改你的MS SQL数据库配置,加上AUTOCOMMIT: False,确保事务上下文能正确接管提交逻辑:

'mssql': {
    'ENGINE': 'sql_server.pyodbc',
    'NAME': '----',
    'HOST': '----',
    'USER': '----',
    'PASSWORD': '----',
    'AUTOCOMMIT': False,  # 新增这行,禁用默认自动提交
}

2. 确保事务和MS SQL连接绑定到位

有时候transaction.atomic(using='mssql')在旧版Django里会“飘”,可以试试显式拿到MS SQL连接再手动控制事务,更稳妥:

from django.db import connections

try:
    # 显式获取MS SQL连接
    mssql_conn = connections['mssql']
    mssql_conn.set_autocommit(False)
    
    with open(filepath, 'r', newline='\n') as clean_file:
        for row in clean_file:
            measurement = json.loads(row)
            current_measurement = Measurementdata(
                mea_datetime=measurement['imp_datetime'],
                dun=measurement['dun_id'],
                exp=measurement['exp_id'],
                ptr=measurement['ptr_id'],
                mea_value=measurement['imp_value']
            )
            # 显式指定用MS SQL连接保存
            current_measurement.save(using='mssql')
    
    # 手动提交事务
    mssql_conn.commit()
except Exception as e:
    # 异常时手动回滚
    mssql_conn.rollback()
    raise e
finally:
    # 恢复自动提交,不影响其他操作
    mssql_conn.set_autocommit(True)

3. 导入速度慢?用批量插入直接起飞

哪怕事务正常了,逐行save()的效率也低得离谱——这也是你觉得慢5倍的关键。换成bulk_create()批量插入,速度能提升一个数量级:

try:
    with transaction.atomic(using='mssql'):
        batch_size = 1000  # 可以根据服务器性能调整,比如500或2000
        batch = []
        
        with open(filepath, 'r', newline='\n') as clean_file:
            for row in clean_file:
                measurement = json.loads(row)
                obj = Measurementdata(
                    mea_datetime=measurement['imp_datetime'],
                    dun=measurement['dun_id'],
                    exp=measurement['exp_id'],
                    ptr=measurement['ptr_id'],
                    mea_value=measurement['imp_value']
                )
                batch.append(obj)
                
                # 攒够一批就插入
                if len(batch) >= batch_size:
                    Measurementdata.objects.using('mssql').bulk_create(batch)
                    batch = []
            
            # 处理最后一批不足batch_size的记录
            if batch:
                Measurementdata.objects.using('mssql').bulk_create(batch)
except Exception as e:
    # 事务块里异常会自动回滚,不用手动操作
    print(f"导入失败,已回滚所有操作: {str(e)}")

注意:Django 1.11.x的bulk_create()对MS SQL是支持的,但如果你的模型有自定义主键生成逻辑,可能需要额外调整,不过看你的模型字段应该没问题。

验证效果

改完之后再看日志,应该能看到BEGIN TRANSACTION的记录,导入速度会明显提升,而且异常时所有已插入的数据都会被回滚。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:27:16