使用 SSH 隧道从远程服务器上的 MariaDB 读取数据

Read data from MariaDB on remote server with SSH tunnel

以下设置:在我的本地 Windows 机器上,我 运行 Spyder 和 Python 3.5。此外,我有一个带有 MariaDB 的远程 Ubuntu 服务器。我想要做的是使用 SSH 隧道和 sqlalchemy 将数据库中的数据加载到 Spyder。

我正在寻找的两个解决方案是:

(i) 将 PuTTY 用于 SSH 隧道到服务器的解释 here 然后在 Spyder 中:

import mysql.connector
from sqlalchemy import create_engine

import pandas as pd

engine = create_engine('mysql+mysqlconnector://un_db:pw_db@127.0.0.1/db')
dbconn = engine.connect()

rslt = dbconn.execute("SELECT * FROM table WHERE col1=x AND col2=y;")
df = pd.DataFrame(rslt.fetchall())
df.columns = rslt.keys()

这在性能方面效果很好,但我已经打开 PuTTY 并建立 SSH 隧道作为过程中的额外步骤。

(ii) 使用包 sshtunnel,从而避免 PuTTY 额外步骤:

from sshtunnel import SSHTunnelForwarder

import mysql.connector
from sqlalchemy import create_engine

import pandas as pd

server = SSHTunnelForwarder(
    (hostname, 22),
    ssh_username=un_server, \
    ssh_password=pw_server,
    remote_bind_address=('127.0.0.1', 3306))

server.start()

engine = create_engine('mysql+mysqlconnector://un_db:pw_db@127.0.0.1:' \
    + str(server.local_bind_port) + '/db')
dbconn = engine.connect()

rslt = dbconn.execute("SELECT * FROM table WHERE col1=x AND col2=y;")
df = pd.DataFrame(rslt.fetchall())
df.columns = rslt.keys()

建立 SSH 隧道一切正常(我认为)但是当我执行查询时,Spyder 中的 IPython 控制台挂起。

问题:为什么我的用例适用于 PuTTY 但不适用于包 sshtunnel?通过 PuTTY 的 SSH 隧道和通过包 sshtunnel 的 SSH 隧道之间有区别吗?

你有两个相似的解决方案。

(i) 在这种情况下,您创建一个转发过程。 (不是 python 进程)

(ii) 在这种情况下 server.start() 启动新的 python 转发线程。这个线程做类似的工作。但它是 python 个线程,线程将一直工作直到它停止。也许这就是您遇到问题的原因。

根据问题,我可以提出三个解决方案。

  1. 您可以使用sshtunnel创建转发过程,如PuTTY。来自自述文件:python -m sshtunnel -U username -P password -L :3306 -R 127.0.0.1:3306 -p 22 localhost

  2. 您可以只使用 server.stop() 来停止 sshtunnel 转发线程。

  3. 也可以使用with语句语法自动停止 (sshtunnel#example-2)

我将驱动程序从 mysql.connector 切换到 MySQLdb,新的解决方案 (ii) 现在也有效:

from sshtunnel import SSHTunnelForwarder
import MySQLdb as mdb
import pandas as pd

server = SSHTunnelForwarder(
    (hostname, 22),
    ssh_username=un_server, \
    ssh_password=pw_server,
    remote_bind_address=('127.0.0.1', 3306))

server.start()

con = mdb.connect('127.0.0.1', un_db, pw_db, port=server.local_bind_port)

df = pd.read_sql("SELECT * FROM table WHERE col1=x AND col2=y", con)

con.close()
server.stop()