web-dev-qa-db-ja.com

Python + SQLAlchemyを使用してMySQLデータベースをリモートで接続する方法

MySQLにリモートでアクセスするのが困難です。 SSHトンネルを使用し、Python + SQLALchemyを使用してデータベースMySQLに接続したい。

コンソールでMySQLクライアントを使用し、「ptotocol=TCP」を指定すると、すべて正常です。私はコマンドを使用します:

mysql -h localhost —protocol=TCP -u USER -p

SSHトンネルを介してリモートデータベースにアクセスできます。

ただし、Python + SQLAchemyを使用してデータベースに接続する場合、—protocol=TCPのようなオプションは見つかりません。そうしないと、ローカルMySQLデータベースにしか接続できません。教えてください、SQLAlchemyを使用してそれを行う方法はありますか。

10
strevg

この問題に対する古典的な答えは、「特殊名」localhostの代わりに127.0.0.1またはホストのIPまたはホスト名を使用することです。 ドキュメント から:

[...] Unix上のlocalhostへの接続は、デフォルトでUnixソケットファイルを使用して行われます。

以降:

Unixでは、MySQLプログラムはホスト名localhostを特別に処理します。他のネットワークベースのプログラム。 localhostへの接続の場合、MySQLプログラムはUnixソケットファイルを使用してローカルサーバーへの接続を試みます。これは、ポート番号を指定するために--portまたは-Pオプションが指定されている場合でも発生します。クライアントがローカルサーバーにTCP/IP接続を行うようにするには、-Hostまたは-hを使用して、ホスト名の値127.0.0.1、またはIPアドレスまたはローカルサーバーの名前を指定します。


ただし、この単純なトリックはあなたのケースでは機能しないように見えるため、何らかの方法でforceを使用する必要がありますTCPソケット。コマンドラインでmysqlを呼び出すときは、--protocol tcpオプションを使用します。

here で説明したように、SQLAlchemyから、connect_argsキーワード引数を使用して、関連オプション(ある場合)をURLオプションとしてドライバーに渡すことができますまたは

たとえば、PyMySQLを使用して、その目的のためにセットアップしたテストシステム(MariaDB 10.0.12、SQLAlchemy 0.9.8およびPyMySQL 0.6.2)では、次の結果が得られました。

>>> engine = create_engine(
      "mysql+pymysql://sylvain:passwd@localhost/db?host=localhost?port=3306")
#                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
#                               Force TCP socket. Notice the two uses of `?`
#                               Normally URL options should use `?` and `&`  
#                               after that. But that doesn't work here (bug?)
>>> conn = engine.connect()
>>> conn.execute("SELECT Host FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = CONNECTION_ID()").fetchall()
[('localhost:54164',)]

# Same result by using 127.0.0.1 instead of localhost: 
>>> engine = create_engine(
      "mysql+pymysql://sylvain:[email protected]/db?host=localhost?port=3306")
>>> conn = engine.connect()
>>> conn.execute("SELECT Host FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = CONNECTION_ID()").fetchall()
[('localhost:54164',)]

# Alternatively, using connect_args:
>>> engine = create_engine("mysql+pymysql://sylvain:passwd@localhost/db",
                       connect_args= dict(Host='localhost', port=3306))
>>> conn = engine.connect()
>>> conn.execute("SELECT Host FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = CONNECTION_ID()").fetchall()
[('localhost:54353',)]

お気づきのように、両方ともTCP接続を使用します(ホスト名の後のポート番号のためにそれを知っています)。

>>> engine = create_engine(
      "mysql+pymysql://sylvain:passwd@localhost/db?unix_socket=/path/to/mysql.sock")
#                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#                               Specify the path to mysql.sock in
#                               the `unix_socket` option will force
#                               usage of a UNIX socket

>>> conn = engine.connect()
>>> conn.execute("SELECT Host FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = CONNECTION_ID()").fetchall()
[('localhost',)]

# Same result by using 127.0.0.1 instead of localhost: 
>>> engine = create_engine(
      "mysql+pymysql://sylvain:[email protected]/db?unix_socket=/path/to/mysql.sock")
>>> conn = engine.connect()
>>> conn.execute("SELECT Host FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = CONNECTION_ID()").fetchall()
[('localhost',)]

# Alternatively, using connect_args:
>>> engine = create_engine("mysql+pymysql://sylvain:passwd@localhost/db",
                       connect_args= dict(unix_socket="/path/to/mysql.sock"))
>>> conn = engine.connect()
>>> conn.execute("SELECT Host FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = CONNECTION_ID()").fetchall()
[('localhost',)]

hostnameの後にポートがありません:これはUNIXソケットです。

18
Sylvain Leroux