以下设置:在我的本地Windows机器上,我使用Python 3.5运行Spyder。此外,我有一个带有MariaDB的远程Ubuntu服务器。我想要做的是使用SSH隧道和sqlalchemy将数据从数据库加载到Spyder。
我正在研究的两个解决方案是:
(i)按照here所述,然后在Spyder中使用PuTTY进行SSH隧道到服务器:
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的一个隧道有什么区别吗?
答案 0 :(得分:0)
您有两种类似的解决方案。
(i)在这种情况下,您将创建转发过程。 (不是python进程)
(ii)在这种情况下server.start()
启动新的python转发线程。这个线程做了类似的工作。但它是python线程,线程将一直工作,直到它被停止。也许这就是你遇到问题的原因。
基于这个问题,我可以提出三种解决方案。
您可以使用sshtunnel
创建转发流程,例如PuTTY
。来自自述文件:python -m sshtunnel -U username -P password -L :3306 -R 127.0.0.1:3306 -p 22 localhost
您可以使用server.stop()
来停止sshtunnel
转发线程。
您还可以使用with
语句语法进行自动停止
(sshtunnel#example-2)
答案 1 :(得分:0)
我将驱动程序从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()