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

如何预防或减少Django应用操作MySQL时出现的死锁问题

Django+MySQL高并发场景Payment表插入死锁解决方案

核心根因确认

你推测外键为死锁诱因的判断符合该场景的特征:
插入Payment实例时,MySQL会自动对to_member、from_member两个外键关联的Member表行加共享锁(S锁),高并发下如果两个事务的加锁顺序相反(比如事务1先锁用户A再锁用户B,事务2先锁用户B再锁用户A),就会触发循环等待条件,直接产生死锁。

可落地解决方案

  • 强制统一加锁顺序(根除90%以上此类死锁)
    所有涉及多Member行关联的操作,统一按Member ID升序的顺序加排他锁,再执行Payment创建,从根本上消除循环等待的死锁条件,代码示例如下:
    from django.db import transaction
    
    with transaction.atomic():
        # 统一按ID升序排序,保证所有事务加锁顺序完全一致
        if from_member.id > to_member.id:
            from_member, to_member = to_member, from_member
        # 对两个关联Member行加排他锁,阻塞其他事务同时操作这两行
        Member.objects.select_for_update().filter(id__in=[from_member.id, to_member.id])
        # 再执行Payment创建逻辑
        payment = Payment.objects.create(
            to_member=to_member,
            to_name=to_member.username,
            from_member=from_member,
            from_name=from_member.username,
            description="Resubscription",
            type='resubscription',
            amount=5.00,
            currency=from_member,
            processor='e-wallet'
        )
    
  • 调整MySQL事务隔离级别
    默认的REPEATABLE-READ(可重复读)隔离级别会开启间隙锁,大幅提升死锁概率,可将MySQL全局/会话隔离级别调整为READ-COMMITTED(读已提交),自动关闭间隙锁,该调整对绝大多数业务的一致性无影响,可直接在生产环境生效。
  • 缩短事务持有锁的时间
    检查Payment创建逻辑是否包裹在大事务中,尽可能将非原子性操作移出事务,缩短锁持有时长,降低锁冲突概率。不要随意调整innodb_lock_wait_timeout等锁配置参数,默认参数足够支撑业务,乱改容易引发系统整体锁死。
  • 新增死锁重试兜底机制
    可添加死锁异常自动重试逻辑,避免用户侧感知报错,代码示例如下:
    import time
    from django.db import OperationalError
    from functools import wraps
    
    def deadlock_retry(max_retries=3):
        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                retries = 0
                while retries < max_retries:
                    try:
                        return func(*args, **kwargs)
                    except OperationalError as e:
                        if "Deadlock found" in str(e) and retries < max_retries - 1:
                            retries += 1
                            time.sleep(0.1 * retries)
                            continue
                        raise
            return wrapper
        return decorator
    
    # 用法
    @deadlock_retry(max_retries=3)
    def create_resubscription_payment(from_member, to_member):
        # 上述事务+加锁+创建Payment逻辑
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 05:36:03