之前寫了個小程序Node News,用到了MySQL數據庫,在本地測試均沒神馬問題。放上服務器運行一段時間后,偶然發現打開頁面的時候頁面一直處於等待狀態,直到Nginx返回超時錯誤。於是上服務器檢查了遍,發現程序仍然在運行,且能正確記錄每次的請求,再修改代碼跟蹤調試,原來是在查詢數據庫的時候,回調一直沒有被執行,程序就掛在那里了。
想了很久也想不明白為神馬mysql模塊沒有執行回調,最后突然想起來去看了下錯誤日志,才發現有個“No reconnection after connection lost”錯誤沒有被捕捉到,原來是連接丟失了,上github上看了下文檔和issues,上面說到連接丟失后不會自動重新連接,會觸發error事件。我趕緊給程序添加了斷線后自動重連功能,現在已正常運行了10多天。
MySQL中有一個名叫wait_timeout的變量,表示操作超時時間,當連接超過一定時間沒有活動后,會自動關閉該連接,這個值默認為28800(即8小時)。
自動重連數據庫的代碼:
function handleError (err) { if (err) { // 如果是連接斷開,自動重新連接 if (err.code === 'PROTOCOL_CONNECTION_LOST') { connect(); } else { console.error(err.stack || err); } } } // 連接數據庫 function connect () { db = mysql.createConnection(config); db.connect(handleError); db.on('error', handleError); } var db; connect();
網上流傳的大多數使用mysql模塊的代碼,往往忽略了這個問題,一不小心就讓一撥又一撥的人往坑里踩了。
有童鞋回復問使用pool又會怎樣,於是去看了下mysql模塊的源碼:目前可在npm中安裝到的最新版本為2.0.0-alpha7,使用mysql.createPool()來創建的pool沒辦法自動處理連接被關閉的問題,但是在github上的版本已經修復了(應該還沒發布到npm上),當觸發了connection的error事件時,會把該connection對象從連接池中移除。(源碼:https://github.com/felixge/node-mysql/blob/master/lib/Pool.js#L119 )
使用pool的代碼:
var mysql = require('mysql'); var pool = mysql.createPool(config); pool.getConnection(function(err, connection) { // Use the connection connection.query( 'SELECT something FROM sometable', function(err, rows) { // And done with the connection. connection.end(); // Don't use the connection here, it has been returned to the pool. }); });
參考: 《Nodejs使用mysql》 《No reconnection after connection lost》 《mysql自動斷開連接的問題處理方案》 《MySQL數據庫連接超時(wait_timeout)問題的處理》
