解决django.db.utils.OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction') 死锁问题

发布时间 2023-07-07 16:52:12作者: 就学45分钟

原因:因为设置了SESSION_SAVE_EVERY_REQUEST=Ture,导致每个接口没有修改的状态下也更改session的过期时间。

  1. 查看代码发现SessionMiddleware源码,遇到UpdateError异常直接抛出。

    try:
        request.session.save()
    except UpdateError:
        raise SuspiciousOperation(
            "The request's session was deleted before the "
            "request completed. The user may have logged "
            "out in a concurrent request, for example."
        )
    
  2. 创建一个新的中间件类,继承自SessionMiddleware

    import time
    from django.db import transaction
    from django.contrib.sessions.backends.base import UpdateError
    from django.contrib.sessions.middleware import SessionMiddleware
    
    
    class CustomSessionMiddleware(SessionMiddleware):
        # 继承SessionMiddleware 遇到异常重试3次
    
        def process_response(self, request, response):
            try:
                return super().process_response(request, response)
            except Exception as e:
                print('errors: {}'.format(e))
                max_retries = 3
                retries = 0
                success = False
                while retries < max_retries and not success:
                    try:
                        with transaction.atomic():
                            request.session.save()
                        success = True
                    except UpdateError:
                        print('试图获得锁时发现死锁;尝试重新启动事务!')
                        retries += 1
                        time.sleep(1)
    
                if not success:
                    # 处理超过最大重试次数的情况
                    if request.method == "POST":
                        print(request.body, '================>')
                    else:
                        print(request.GET, '================>')
                    print('OperationalError 异常已经重试最大次数')
            return response
    
    
  3. 在Django的配置文件(settings.py)中将默认的SessionMiddleware替换为自定义的中间件。

    MIDDLEWARE = [
        # 'django.contrib.sessions.middleware.SessionMiddleware',
        # 重写SessionMiddleware
        'middleware.session.CustomSessionMiddleware',
    ]