如何远程使用Python + SQLAlchemy连接MySQL数据库?

str*_*evg 10 python mysql tcp sqlalchemy ssh-tunnel

我无法远程访问MySQL.我使用SSH隧道,并希望使用Python + SQLALchemy连接数据库MySQL.

当我在我的控制台中使用MySQL-client并指定" ptotocol=TCP"时,一切都很好!我用命令:

mysql -h localhost —protocol=TCP -u USER -p
Run Code Online (Sandbox Code Playgroud)

我通过SSH隧道访问远程数据库.

但是,当我想使用Python + SQLAchemy连接到数据库时,我找不到像这样的选项,—protocol=TCP 否则,我只连接到本地MySQL数据库.请告诉我,有没有办法使用SQLAlchemy来做到这一点.

Syl*_*oux 19

这个问题的经典答案是使用主机127.0.0.1IP主机名而不是"特殊名称" localhost.从文档:

默认情况下,使用Unix套接字文件在Unix上连接到localhost

然后:

在Unix上,MySQL程序特别对待主机名localhost,其方式可能与您期望的与其他基于网络的程序相比有所不同.对于与localhost的连接,MySQL程序尝试使用Unix套接字文件连接到本地服务器.即使给出--port或-P选项指定端口号,也会发生这种情况.要确保客户端与本地服务器建立TCP/IP连接,请使用--host或-h指定主机名值127.0.0.1,或本地服务器的IP地址或名称.


但是,这个简单的技巧在您的情况下似乎不起作用,因此您必须以某种方式强制使用TCP套接字.正如您自己解释的那样,在mysql命令行上调用时,您可以使用该--protocol tcp选项.

正如解释在这里,从SQLAlchemy的,你可以通过相关选项(如果有的话)到驱动程序无论是作为URL选项使用connect_args关键字参数.

例如,在我为此设置的测试系统上使用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:passwd@127.0.0.1/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',)]
Run Code Online (Sandbox Code Playgroud)

正如您所注意到的,两者都将使用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:passwd@127.0.0.1/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',)]
Run Code Online (Sandbox Code Playgroud)

主机名后没有端口:这是一个UNIX套接字.


jgb*_*rah 7

在我的设置中(我使用的是mysql-python)只是在MySQL SQLAlchemy url中使用127.0.0.1而不是localhost.我正在使用的完整网址(具有本地端口3307的隧道)是:

mysql:/user:passwd@127.0.0.1:3307/
Run Code Online (Sandbox Code Playgroud)

我正在使用SQLAlchemy 1.0.5,但我想这并不重要......

  • 实际上,127.0.0.1是localhost,@ BK435,但它不适用于localhost而不是127.0.0.1.这似乎是由于musql如何处理"localhost",坚持通过文件系统套接字而不是TCP套接字进行连接.这就是问题中提到的选项--protocol = tcp for mysql的原因.但似乎127.0.0.1可以解决问题,并且比当前的答案更简单. (2认同)

spa*_*row 5

这对我有用:

import pandas as pd
import pymysql
from sqlalchemy import create_engine

cnx = create_engine('mysql+pymysql://<username>:<password>@<host>/<dbname>')    
df = pd.read_sql('SELECT * FROM <table_name>', cnx) #read the entire table
Run Code Online (Sandbox Code Playgroud)

像这样将凭据添加到 mysql 数据库的地方:

CREATE USER '<username>' IDENTIFIED BY '<password>';
GRANT ALL PRIVILEGES ON *.* TO '<username>' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Run Code Online (Sandbox Code Playgroud)

  • 微小的补充,可能还需要端口。“mysql+pymysql://&lt;用户名&gt;:&lt;密码&gt;@&lt;主机&gt;:&lt;端口&gt;/&lt;数据库名称&gt;” (3认同)