34

オリジナル: 最近、古いコードの一部から MySQL OperationalErrors が発生し始めましたが、問題を追跡できないようです。以前は機能していたので、ソフトウェアの更新で何かが壊れたのではないかと思いました。nginxでdjango runfcgiでpython 2.7を使用しています。これが私の元のコードです:

ビュー.py

DBNAME = "test"
DBIP = "localhost"
DBUSER = "django"
DBPASS = "password"
db = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME)
cursor = db.cursor()

def list(request):
    statement = "SELECT item from table where selected = 1"
    cursor.execute(statement)
    results = cursor.fetchall()

次のことを試しましたが、まだ機能しません。

ビュー.py

class DB:
    conn = None
    DBNAME = "test"
    DBIP = "localhost"
    DBUSER = "django"
    DBPASS = "password"
def connect(self):
    self.conn = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME)
def cursor(self):
    try:
        return self.conn.cursor()
    except (AttributeError, MySQLdb.OperationalError):
        self.connect()
        return self.conn.cursor()

db = DB()
cursor = db.cursor()

def list(request):
    cursor = db.cursor()
    statement = "SELECT item from table where selected = 1"
    cursor.execute(statement)
    results = cursor.fetchall()

現在、私の唯一の回避策は、MySQLdb.connect()mysql を使用する各関数で行うことです。manage.py runserverまた、django を使用すると、nginx がこれらのエラーをスローする一方で、この問題は発生しないことに気付きました。list()サーバーの起動から数秒以内に呼び出されているため、接続でタイムアウトしているとは思えません。私が使用しているソフトウェアに、これが壊れる原因となるアップデートはありましたか?これに対する修正はありますか?

編集:関数をデーモン化するためのミドルウェアを最近書きましたが、これが問題の原因であることに気付きました。しかし、私はその理由を理解できません。これがミドルウェアのコードです

def process_request_handler(sender, **kwargs):
    t = threading.Thread(target=dispatch.execute,
        args=[kwargs['nodes'],kwargs['callback']],
        kwargs={})
    t.setDaemon(True)
    t.start()
    return
process_request.connect(process_request_handler)
4

13 に答える 13

41

MySQLのドキュメントによると、クライアントがサーバーに質問を送信できない場合、エラー メッセージが表示されます。これは、サーバー自体が接続を閉じている可能性が高いためです。最も一般的なケースでは、サーバーは (デフォルト) 8 時間後にアイドル状態の接続を閉じます。これはサーバー側で構成可能です。

MySQLのドキュメントには、状況に適合するかどうかを調べる価値のある、他にも考えられる原因がいくつか記載されています。

connect()すべての関数を呼び出す (新しい接続を不必要に作成する可能性がある) 代わりにping()、接続オブジェクトのメソッドを使用して調査することもできます。これにより、自動再接続を試行するオプションを使用して接続がテストされます。この方法に関する適切なドキュメントping()オンラインで見つけるのに苦労しましたが、この質問への回答が役立つ場合があります。

トランザクションを処理する場合、自動再接続は危険な場合があることに注意してください。これは、再接続によって暗黙のロールバックが発生するように見えるためです (自動再接続が MySQLdb 実装の機能ではない主な理由のようです)。

于 2013-01-10T22:26:47.097 に答える
2

これは、DB 接続がメイン スレッドから子スレッドにコピーされることが原因である可能性があります。Python のマルチプロセッシング ライブラリを使用してさまざまなプロセスを生成するときに、同じエラーに直面しました。分岐中に接続オブジェクトがプロセス間でコピーされ、子スレッドで DB 呼び出しを行うときに MySQL OperationalErrors が発生します。

これを解決するための良いリファレンスは次のとおりです: Django multiprocessing and database connections

于 2018-10-12T15:36:38.740 に答える
1

あるスレッドで mysql 接続オブジェクトを作成し、それを別のスレッドで使用することが許可されているかどうかを確認してください。

禁止されている場合は、スレッドごとの接続に threading.Local を使用します。

class Db(threading.local):
    """ thread-local db object """
    con = None

    def __init__(self, ...options...):
        super(Db, self).__init__()
        self.con = MySQLdb.connect(...options...)

db1 = Db(...)


def test():
    """safe to run from any thread"""
    cursor = db.con.cursor()
    cursor.execute(...)
于 2013-01-09T10:48:49.423 に答える
1

このような警告に関する最も一般的な問題は、アプリケーションがwait_timeoutMySQL の値に達したという事実です。

Flask アプリでも同じ問題が発生しました。

これが私が解決した方法です:

$ grep timeout /etc/mysql/mysql.conf.d/mysqld.cnf 
# https://support.rackspace.com/how-to/how-to-change-the-mysql-timeout-on-a-server/
# wait = timeout for application session (tdm)
# inteactive = timeout for keyboard session (terminal)
# 7 days = 604800s / 4 hours = 14400s 
wait_timeout = 604800
interactive_timeout = 14400

観察: MySQL バッチ モードで変数を検索すると、値がそのまま表示されます。SHOW VARIABLES LIKE 'wait%';しかし、またはを実行するSHOW VARIABLES LIKE 'interactive%';と、 に設定された値interactive_timeoutが両方の変数に表示され、理由はわかりませんが、実際には、「/etc/mysql/mysql.conf.d/」で各変数に設定された値がmysqld.cnf' は、MySQL によって尊重されます。

于 2016-09-13T15:40:39.707 に答える
0

MySQL は接続が切断された理由を報告せず、単に消えるだけなので、このエラーは不可解です。

この種の断線には多くの原因があるようです。私が見つけたのは、クエリ文字列が大きすぎると、サーバーが切断されることです。これはおそらくmax_allowed_packets設定に関係しています。

于 2016-10-31T12:34:19.343 に答える
0

SQLAlchemy には、ping を使用して接続の鮮度について悲観的になる方法についての素晴らしい記事があります。

http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic

そこから、

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool

@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
    cursor = dbapi_connection.cursor()
    try:
        cursor.execute("SELECT 1")
    except:
        # optional - dispose the whole pool
        # instead of invalidating one at a time
        # connection_proxy._pool.dispose()

        # raise DisconnectionError - pool will try
        # connecting again up to three times before raising.
        raise exc.DisconnectionError()
    cursor.close()

そして、上記が機能することを確認するためのテスト:

from sqlalchemy import create_engine
e = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)
c1 = e.connect()
c2 = e.connect()
c3 = e.connect()
c1.close()
c2.close()
c3.close()

# pool size is now three.

print "Restart the server"
raw_input()

for i in xrange(10):
    c = e.connect()
    print c.execute("select 1").fetchall()
    c.close()
于 2013-07-22T15:10:39.617 に答える
0

このコードは何歳ですか?Django では、少なくとも .96 以降、設定でデータベースが定義されています。私が考えることができる唯一の他のことは、少し変更されたマルチデータベースのサポートですが、それでも1.1または1.2でした.

特定のビューに特別な DB が必要な場合でも、設定で定義した方がよいと思います。

于 2013-01-04T20:59:08.203 に答える