ホームページ  >  記事  >  バックエンド開発  >  Django データベース接続切断の問題の解決 (例で説明)

Django データベース接続切断の問題の解決 (例で説明)

不言
不言転載
2018-12-29 10:35:433724ブラウズ

この記事の内容は、Django のデータベース接続切断問題の解決方法 (例を挙げて説明) であり、一定の参考価値がありますので、困っている友人は参考にしていただければ幸いです。

問題

Django で mysql を使用すると、データベース接続が失われることがあります。通常、エラーには次の 2 種類が含まれます。

1. `OperationalError: (2006, 'MySQL server has gone away')`  
1. `OperationalError: (2013, 'Lost connection to MySQL server during query')`

クエリ mysql グローバル変数 SHOWグローバル変数 ;wait_timeout が表示されます。この変数は接続のアイドル時間を表します。クライアントが 1 つの接続を使用してデータベースを複数回クエリする場合、クエリが継続的であれば問題はありませんが、複数のクエリの後にクエリが wait_timeout を超えて一時停止すると、データベース接続が失われ、データベース接続が失われます。

再現

Django を使用して次回問題を再現します:

1. mysql の wait_timeout を 10 秒に設定し、django を入力します。シェル シミュレーション クエリ (次のエラー メッセージの一部のみが保持されます)

In[1]:import time
In[2]:from django.contrib.auth.models import User
In[3]:list(User.objects.filter(id=1))
Out[3]:[<User: admin>]
In[4]:time.sleep(15) # 模拟比较慢的代码(其中没有查询数据库的代码),或者空闲什么都不操作一段时间,此时间要比`wait_timeout`大一些
list(User.objects.filter(id=1))
Traceback (most recent call last):
  File "<ipython-input-4-3574ae8220ee>", line 1, in <module>
    list(User.objects.filter(id=1))

  File "/usr/lib/python3.6/site-packages/pymysql/connections.py", line 1037, in _read_bytes
    CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
django.db.utils.OperationalError: (2013, 'Lost connection to MySQL server during query')

Seeking

したがって、上記の問題は基本的に、アイドル時間が長すぎることがエラーの原因であることを示しています。 。
不要なデータベース接続とクローズを減らすために、Django はデータベース接続を再利用します。リクエストが開始されると、接続を保存するための接続プールが確立されます。その後、リクエストごとに接続が再利用されます。私の推測では、Django は wait_timeout よりも長く接続を保存すると思いますが、保存時間が短ければ、接続を再確立してこのエラーを回避できます。
はい、公式ドキュメントでもこの問題について説明されており、データベースの CONN_MAX_AGE パラメーターを設定します。例:

DATABASES = {
    "default": {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': '',
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
            'CONN_MAX_AGE': 9  # 比wait_timeout小一些
    }
}

テストしたところ、思ったほど単純ではないことがわかりました。それでもエラーが発生するのはなぜですか?このすべての背後にあるのは、人間性の歪みですか、それとも道徳の喪失ですか? 次回のエピソード「Breakthrough」をご覧ください。

ブレークスルー

Django ソース コードで CONN_MAX_AGE を検索した後、手がかりを追って、Django が失敗した接続をどのように閉じるかを調べました。 django.db.close_old_connections()

# Register an event to reset transaction state and close connections past
# their lifetime.
def close_old_connections(**kwargs):
    for conn in connections.all():
        conn.close_if_unusable_or_obsolete()

signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)
フォーカスは最後の 2 行にあります。このメソッドは、シグナルを通じて特定のイベントが実装されるときに実行されます。名前が示すように、2 つの特定のイベントは次のとおりです。リクエストの開始とリクエストの終了。私たちが報告したエラーは 1 つのリクエストで発生したものであるため、この方法は通常は効果がなく、リクエストごとに接続を閉じて再確立するだけです。

解決策

問題を再現する django シェルを閉じずに、次のコードの実行を続けます:

In[5]:from django.db import close_old_connections
In[6]:close_old_connections()
In[7]:list(User.objects.filter(id=1))
Out[7]: [<User: admin>]
Call django.db.close_old_connections再度クエリを実行すると、エラーはなくなりました。

このエラーを回避したい場合は、各データベース クエリを実行する前に django.db.close_old_connections メソッドを呼び出す必要があります。

1. データベースのクエリは 1 つのリクエストで継続的に実行され、リクエストのたびにこのメソッドを呼び出す必要がないため、通常はこのような問題は発生しませんが、これは杞憂です。

2. リクエストに大量のデータが含まれる場合があり、データベースがクエリされ、その後、一定期間、他の処理 (データベースに関係しない) が実行されます。最初にクエリが実行され、次にデータが処理され、Excel が生成され、ファイルが保存され、URL が生成されます。これには非常に長い時間がかかることが知られているため、最終的な URL がデータベースに保存されるときに接続が失われないように、最初に django.db.close_old_connections を呼び出すことが最善です。

以上がDjango データベース接続切断の問題の解決 (例で説明)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。