2015-03-30 21 views
7

Tôi gặp khó khăn khi truy cập MySQL từ xa. Tôi sử dụng đường hầm SSH và muốn kết nối cơ sở dữ liệu MySQL bằng Python + SQLALchemy.Làm thế nào để kết nối cơ sở dữ liệu MySQL bằng Python + SQLAlchemy từ xa?

Khi tôi sử dụng MySQL-client trong giao diện điều khiển của tôi và chỉ định "ptotocol=TCP", sau đó mọi thứ đều tốt! Tôi sử dụng lệnh:

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

Tôi có quyền truy cập cơ sở dữ liệu từ xa thông qua đường hầm SSH.

Tuy nhiên, khi tôi muốn kết nối với cơ sở dữ liệu bằng Python + SQLAchemy, tôi không thể tìm thấy tùy chọn như —protocol=TCP Nếu không, tôi chỉ kết nối với cơ sở dữ liệu MySQL cục bộ. Hãy cho tôi biết, có cách nào để làm điều đó bằng cách sử dụng SQLAlchemy không.

+0

thiết lập đường hầm ssh, sau đó trỏ mysql cục bộ của bạn tại cổng hầm trên máy cục bộ. mysql sẽ không biết nó đang được tunneled, và ssh sẽ chăm sóc chuyển hướng mọi thứ mà nó nên đi. Đường hầm –

+0

đã được cài đặt từ X.X.X.X: 3306 -> localhost: 3306 Có lẽ tôi cần đặt đường hầm đến một cổng khác, ví dụ: localhost: 3307? – strevg

+0

@strevg Để làm rõ mọi thứ: bạn có một máy chủ MySQL đang chạy trên máy chủ cục bộ của bạn. Và một máy chủ MySQL thứ hai được truy cập từ xa thông qua một đường hầm SSH. Cả hai đều chạy đồng thời? Máy chủ nào bị ràng buộc với cổng nào trên máy chủ cục bộ của bạn? –

Trả lời

12

Câu trả lời cổ điển đến vấn đề này là sử dụng 127.0.0.1 hoặc chỉ IP của các máy chủ hoặc tên chủ thay vì "tên đặc biệt" localhost. Từ documentation:

[...] Kết nối trên Unix để localhost được thực hiện sử dụng một file socket Unix theo mặc định

Và sau:

Trên Unix, chương trình MySQL đối xử với tên máy chủ localhost đặc biệt, theo một cách mà có thể khác với những gì bạn mong đợi so với mạng- khác các chương trình dựa trên. Đối với các kết nối đến localhost, các chương trình MySQL cố gắng kết nối với máy chủ cục bộ bằng cách sử dụng một tệp socket Unix. Điều này xảy ra ngay cả khi một tùy chọn --port hoặc -P được đưa ra để chỉ định một số cổng. Để đảm bảo rằng máy khách tạo kết nối TCP/IP tới máy chủ cục bộ, hãy sử dụng --host hoặc -h để chỉ định giá trị tên máy chủ lưu trữ là 127.0.0.1 hoặc địa chỉ IP hoặc tên của máy chủ cục bộ.


Tuy nhiên, thủ thuật đơn giản này không xuất hiện để làm việc trong trường hợp của bạn, vì vậy bạn phải bằng cách nào đó lực việc sử dụng một socket TCP. Như bạn đã giải thích điều đó cho mình, khi gọi mysql trên dòng lệnh, bạn sử dụng tùy chọn --protocol tcp.

Như đã giải thích here, từ SQLAlchemy, bạn có thể vượt qua các tùy chọn liên quan (nếu có) cho người lái xe hoặc là tùy chọn URL hoặc sử dụng lập luận connect_args từ khóa.

Ví dụ sử dụng PyMySQL, trên một hệ thống kiểm tra tôi đã thiết lập cho mục đích đó (MariaDB 10.0.12, SQLAlchemy 0.9.8 và 0.6.2 PyMySQL) Tôi có kết quả như sau:

>>> engine = create_engine(
     "mysql+pymysql://sylvain:[email protected]/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:[email protected]/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',)] 

Như bạn thấy, cả hai sẽ sử dụng kết nối TCP (Tôi biết rằng vì số cổng sau tên máy chủ).Mặt khác:

>>> engine = create_engine(
     "mysql+pymysql://sylvain:[email protected]/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:[email protected]/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',)] 

Không cảng sau hostname: đây là một ổ cắm UNIX.

+1

Rất đẹp. Điều này cũng làm việc cho tôi làm việc với một địa phương (không root) mysql cài đặt, nơi tôi đã có một phi tiêu chuẩn 'cổng' và' unix_socket' tôi cần thiết để thiết lập. –

+0

Thật không may, MySQLdb dường như đã trở nên nghiêm ngặt hơn. Bây giờ bạn nhận được một TypeError, beacuse SQLAlchemy đang đi qua cổng như một chuỗi và MySQLdb mong đợi một int. :/ –

5

Trong thiết lập của tôi (tôi đang sử dụng mysql-python) chỉ cần sử dụng 127.0.0.1 thay vì localhost trong MySQL SQLAlchemy url hoạt động. Url đầy đủ Tôi đang sử dụng chính xác cho kịch bản đó (đường hầm với cổng địa phương 3307) là:

mysql:/user:[email protected]:3307/ 

Tôi đang sử dụng SQLAlchemy 1.0.5, nhưng tôi đoán rằng không quan trọng quá nhiều ...

+2

Thật vậy, 127.0.0.1 là localhost, @ BK435, nhưng nó không hoạt động với localhost thay vì 127.0.0.1. Điều này có vẻ là do làm thế nào musql đề với "localhost", nhấn mạnh trong kết nối thông qua ổ cắm hệ thống tập tin thay vì TCP socket. Đó là lý do tại sao tùy chọn --protocol = tcp cho mysql được đề cập trong câu hỏi. Nhưng có vẻ như 127.0.0.1 thực hiện thủ thuật và đơn giản hơn câu trả lời hiện tại. – jgbarah

Các vấn đề liên quan