2013-06-10 12 views
19

Ho bisogno di una connessione MySQL persistente per la mia app web Node. Il problema è che questo accade su un paio di volte al giorno:Node.js MySQL che necessita di connessione persistente

Error: Connection lost: The server closed the connection. 
at Protocol.end (/var/www/n/node_modules/mysql/lib/protocol/Protocol.js:73:13) 
at Socket.onend (stream.js:79:10) 
at Socket.EventEmitter.emit (events.js:117:20) 
at _stream_readable.js:895:16 
at process._tickCallback (node.js:415:13) 
error: Forever detected script exited with code: 8 
error: Forever restarting script for 2 time 
info: socket.io started 

Ecco il mio codice di connessione:

// Yes I know multipleStatements can be dangerous in the wrong hands. 
var sql = mysql.createConnection({ 
    host: 'localhost', 
    user: 'my_username', 
    password: 'my_password', 
    database: 'my_database', 
    multipleStatements: true 
}); 

sql.connect(); 

function handleDisconnect(connection) { 
    connection.on('error', function(err) { 
     if (!err.fatal) { 
      return; 
     } 
     if (err.code !== 'PROTOCOL_CONNECTION_LOST') { 
      throw err; 
     } 
     console.log('Re-connecting lost connection: ' + err.stack); 
     sql = mysql.createConnection(connection.config); 
     handleDisconnect(sql); 
     sql.connect(); 
    }); 
} 

handleDisconnect(sql); 

Come si può vedere, il codice handleDisconnect non funziona ..

+0

Sarebbe utile sapere quale modulo MySQL stai usando nel nodo. – Sly

+1

Sto usando node-mysql, come indicato dal tag. – apscience

+0

Ah, mi scuso. Non l'ho visto nei tag. – Sly

risposta

33

Utilizzare il pool di connessione mysql. Si riconnetterà quando una connessione si interrompe e si ottiene il vantaggio aggiuntivo di poter effettuare più query SQL allo stesso tempo. Se non si utilizza il pool di database, l'app bloccherà le richieste del database in attesa che terminino le richieste di database attualmente in esecuzione.

Di solito definisco un modulo di database in cui tengo separate le mie query dai miei percorsi. Sembra qualcosa di simile ...

var mysql = require('mysql'); 
var pool = mysql.createPool({ 
    host  : 'example.org', 
    user  : 'bob', 
    password : 'secret' 
}); 

exports.getUsers = function(callback) { 
    pool.getConnection(function(err, connection) { 
    if(err) { 
     console.log(err); 
     callback(true); 
     return; 
    } 
    var sql = "SELECT id,name FROM users"; 
    connection.query(sql, [], function(err, results) { 
     connection.release(); // always put connection back in pool after last query 
     if(err) { 
     console.log(err); 
     callback(true); 
     return; 
     } 
     callback(false, results); 
    }); 
    }); 
}); 
+8

C'è un modo per utilizzare i pool senza refactoring di tutto? Ho dozzine di query SQL nell'app. – apscience

+0

btw, come possiamo conoscere le connessioni massime del server mysql alla volta? – Ddo

+0

Controlla la configurazione di MySQL per "max_connections". http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html – Daniel

13

In risposta a @gladsocc domanda:

Is there a way to use pools without refactoring everything? I have dozens of SQL queries in the app.

Questo è quello che ho finito per edilizia. È un wrapper per la funzione query. Prenderà la connessione, farà la richiesta, quindi rilascerà la connessione.

E lo uso come vorrei normalmente.

db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id) 
      .on('result', function (row) { 
      setData(row); 
      }) 
      .on('error', function (err) { 
      callback({error: true, err: err}); 
      }); 
+0

Ho appena provato a farlo, tuttavia ottengo 'ReferenceError: db is not defined' –

+0

@BrandonStewart nel secondo esempio di codice sei in un altro file, quindi dovresti prendere la connessione come faresti normalmente,' var db = require ('./db.js'); 'da qualche parte in alto – oportocala

16

So che questo è super ritardo, ma ho scritto una soluzione a questo che penso che potrebbe essere un po 'più generico e utilizzabile. Avevo scritto un'app interamente dipendente da connection.query() e il passaggio a un pool interrompeva quelle chiamate.

Ecco la mia soluzione:

var mysql = require('mysql'); 

var pool = mysql.createPool({ 
    host  : 'localhost', 
    user  : 'user', 
    password : 'secret', 
    database : 'test', 
    port  : 3306 
}); 

module.exports = { 
    query: function(){ 
     var sql_args = []; 
     var args = []; 
     for(var i=0; i<arguments.length; i++){ 
      args.push(arguments[i]); 
     } 
     var callback = args[args.length-1]; //last arg is callback 
     pool.getConnection(function(err, connection) { 
     if(err) { 
       console.log(err); 
       return callback(err); 
      } 
      if(args.length > 2){ 
       sql_args = args[1]; 
      } 
     connection.query(args[0], sql_args, function(err, results) { 
      connection.release(); // always put connection back in pool after last query 
      if(err){ 
        console.log(err); 
        return callback(err); 
       } 
      callback(null, results); 
     }); 
     }); 
    } 
}; 

Questo crea un'istanza della piscina una volta, quindi esporta un metodo denominato query. Ora, quando connection.query() viene chiamato ovunque, chiama questo metodo, che prima prende una connessione dal pool, quindi passa gli argomenti alla connessione. Ha l'effetto aggiunto di afferrare prima il callback, quindi può richiamare qualsiasi errore nel prendere una connessione dal pool.

Per utilizzare ciò, è sufficiente richiederlo come modulo al posto di mysql. Esempio:

var connection = require('../middleware/db'); 

function get_active_sessions(){ 
    connection.query('Select * from `sessions` where `Active`=1 and Expires>?;', [~~(new Date()/1000)], function(err, results){ 
    if(err){ 
     console.log(err); 
    } 
    else{ 
     console.log(results); 
    } 
    }); 
} 

Questo appare come la query normale, ma in realtà apre una piscina e afferra una connessione dal pool in background.

+1

un caso d'uso aiuterebbe comunque :) – tomexsans

+0

Ottima soluzione, specialmente quando è necessario mettere in pausa una connessione specifica –

Problemi correlati