一、環境及問題描述
1. 環境
操作系統:win10家庭版,64bit
python版本:Python 2.7.15
mysql版本:mysql 5.4.3
2. 問題描述
最近跟公司申請電腦,預裝win10家庭版,懶得刷回win7,於是將開發環境遷移過來。但是在python上用MySQLdb去連接mysql的時候就直接報錯了:“2003 ,Can't connect to MySQL server on 'localhost' (10061)”。
二、問題解決
1. mysqld開啟
一般像這個問題,搜到最多的其實就是叫檢查mysql后台服務有沒有開啟,可是我這邊的mysqld不僅正在運行,而且還能用Navicat連接上去,故可以排除。
2. my.ini文件
然后就是修改my.ini文件的方法,一般是修改bind-address = 127.0.0.1或0.0.0.0,但是修改還是不起作用。
3. hosts文件
就是在hosts文件里增加一個映射,127.0.0.1 localhost。修改后,重啟電腦,同樣沒有反應。
但是這個修改是很關鍵的,后面會說到。
4. 從localhost到127.0.0.1
后面搜到一個匹配度很高的問題,也是用Navicat可以連接 (主機名也是localhost),但是用python的時候就不行了,這個時候有點覺得是localhost在不同的軟件中的解析問題。
問了一下盆友,盆友說沒用過mysql,但是用過Oracle(愛立信也是土豪公司),意思是Oracle需要配置自己的解析文件,不是系統的hosts文件,叫我可以看看庫函數底層源碼雲雲。
於是我順手在win10的powershell里 敲下:ping localhost,這個時候收到的竟然不是127.0.0.1的回復,而是::1,所以::1是什么鬼?
5. win10 如何解析localhost
實際上,win10解析localhost的時候, 會把 localhost 解析為 ipv6 地址 ::1 而不是 127.0.0.1!所以解決辦法就是改回解析為127.0.0.1:
- 打開注冊表,找到鍵 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\tcpip6\Parameters
- 添加類型為DWORD 名字為 DisabledComponents 的項(已經有了的不用添加直接改值)
- 然后修改值為 20,值類型為16進制
- 保存注冊表,重啟電腦。
重新連接mysql,終於解決問題!
所以問題的關鍵就是系統怎么解析localhost,但是再深入一步,到底在mysql中,以localhost和127.0.0.1兩種方式連接的時候,區別到底在哪里呢?
三、mysql的主機為localhost和127.0.0.1的區別
1. 類unix系統
類Unix系統下,如果不使用-h指定主機名或者使用了localhost,那么會使用unix domain socket與mysql服務器通信;如果host指定為'127.0.0.1',則使用TCP/IP協議進行通信。
2. windows系統
如果mysql在win上跑,如果系統開啟了--enable-named-pipe,然后訪問服務器的時候沒有指定hostname,那么mysql客戶端會以pipe為優先連接,如果連接失敗,那么再會去嘗試使用TCP/IP去連接。你可以指定hostname為.在win下強制使用pipes。
如果host指定為'127.0.0.1',依然是使用TCP/IP協議進行通信。
3. 一點猜測
如上所述,在windows環境下,實際上在底層是無法用localhost的方式去連接mysql的,據說從win10開始會逐漸支持unix domain socket,但是現在用的mysql還是無法用這種方式去連接。
但是如Navicat的軟件或者用python的庫函數,怎么又能用localhost的方式去連接呢?
我猜測想Navicat這種軟件,底層應該會將localhost解析為127.0.0.1,接着才去建立連接。至於python的MySQLdb,則會調用系統的函數去解釋,由於win10將localhost解釋為ipv6的地址,因此才會出問題。
四、參考
1. WIN10 LOCALHOST 解析為 IPV6地址 ::1 的解決辦法
2. mysql中localhost和127.0.0.1的區別
3. Windows 10 17063 開始支持 UNIX Domain Socket
(完)