NodeJS MySQL Dump

Intenté escribir un script cron básico para ejecutar y ‘volcar’ una base de datos mysql. Por alguna razón, cuando ‘salva exitosamente el archivo’, crea el archivo, pero está vacío. Si en lugar de guardar el archivo, realizo un console.log, imprime una cadena vacía. ¿Alguna idea sobre lo que puedo estar haciendo mal?

Gracias por adelantado.

var mysql_backup = function(){ this.backup = ''; this.mysql = require('mysql'), this.init = function(){ this.connection = this.mysql.createConnection({ user: 'root', password: 'root', database: 'test' }); } this.query = function(sql, callback) { this.connection.query(sql, function (error, results, fields) { if (error) { throw error; } if (results.length > 0) { callback(results); } }); } this.get_tables = function(callback){ var me = this; me.query('SHOW TABLES', function(tables) { for (var table in tables){ me.query( 'SHOW CREATE TABLE ' + tables[table].Tables_in_test, function(r){ for (var t in r) { me.backup += "DROP TABLE " + r[t].Table + "\n\n"; me.backup += r[t]["Create Table"] + "\n\n"; } } ) } me.save_backup(); }); } this.save_backup = function(){ var fs = require('fs'); fs.writeFile("./backup_test.txt", this.backup, function(err) { if(err) { console.log(err); } else { console.log("The file was saved!"); } }); } }; var db = new mysql_backup; db.init(); db.get_tables(); db.connection.destroy(); 

El código tal como está escrito ni siquiera llegó a guardar un archivo para mí. Parece que hay algunos problemas. No estoy seguro de si este es el código real o algunas cosas se perdieron en el proceso de copiar y pegar. Sin embargo, según lo que tienes:

Una gran cosa es que nunca se conecta a la base de datos en su código con connection.connect ().

El código que desea ejecutar una vez conectado debe estar dentro de la conexión de llamada connection.connect (). p.ej

 connection.connect(function (err, empty) { if (err) throw new Error ('Panic'); // if no error, we are off to the races... } 

Sin embargo, incluso si refactoriza rápidamente su código para envolver sus últimas líneas dentro de la callback de conexión, aún tendrá problemas, porque está destruyendo la conexión antes de que se realicen varias llamadas SQL, por lo que querrá mover el código en algún tipo de callback final.

Incluso después de hacer eso, todavía tendrá un archivo vacío, porque está llamando a save_backup desde la callback de ‘SHOW TABLES’ en lugar de después de haberlo poblado a través de la callback interna donde obtiene la sentencia CREATE TABLE y rellena el propiedad de copia de seguridad.

Esta es la reescritura mínima de su código que hará lo que pretende. Una cosa importante a tener en cuenta es el “contador” que gestiona cuándo escribir el archivo y cerrar la conexión. Haría otros cambios si fuera mío, incluyendo:

  • Usar ‘self’ en lugar de ‘me’
  • Utilizando un bucle for numérico en lugar de la syntax for (… in …)
  • Tener mis propias devoluciones de llamada caen la convención del nodo de (err, cosas)
  • Un cambio más sustancial es que yo volvería a escribir esto para usar las promesas, ya que al hacerlo puedo ahorrarle un poco de dolor con la confusión inherente a las devoluciones de llamada profundamente anidadas. Personalmente me gusta la biblioteca Q, pero hay varias opciones aquí.

Espero que esto haya ayudado.

 var mysql_backup = function(){ this.backup = ''; this.mysql = require('mysql'); this.init = function(){ this.connection = this.mysql.createConnection({ user : 'root', password : 'root', database : 'test' }); }; this.query = function(sql, callback) { this.connection.query(sql, function (error, results, fields) { if (error) { throw error; } if (results.length > 0) { callback(results); } }); }; this.get_tables = function(callback){ var counter = 0; var me = this; this.query('SHOW TABLES', function(tables) { for (table in tables){ counter++; me.query( 'SHOW CREATE TABLE ' + tables[table].Tables_in_mvc, function(r){ for (t in r) { me.backup += "DROP TABLE " + r[t].Table + "\n\n"; me.backup += r[t]["Create Table"] + "\n\n"; } counter--; if (counter === 0){ me.save_backup(); me.connection.destroy(); } } ) } }); }; this.save_backup = function(){ var fs = require('fs'); fs.writeFile("./backup_test.txt", this.backup, function(err) { if(err) { console.log(err); } else { console.log("The file was saved!"); } }); } }; var db = new mysql_backup; db.init(); db.connection.connect(function (err){ if (err) console.log(err); db.get_tables(function(x){;}); }); 

Actualización: si tiene curiosidad, aquí hay una implementación muy comentada que usa promesas. Tenga en cuenta que sin los comentarios que explican las funciones de la biblioteca Q promise, es algo más corto que la versión original y también ofrece un manejo de errores más completo.

 var MysqlBackup = function(connectionInfo, filename){ var Q = require('q'); var self = this; this.backup = ''; // my personal preference is to simply require() inline if I am only // going to use something a single time. I am certain some will find // this a terrible practice this.connection = require('mysql').createConnection(connectionInfo); function getTables(){ // return a promise from invoking the node-style 'query' method // of self.connection with parameter 'SHOW TABLES'. return Q.ninvoke(self.connection,'query', 'SHOW TABLES'); }; function doTableEntries(theResults){ // note that because promises only pass a single parameter around, // if the 'denodeify-ed' callback has more than two parameters (the // first being the err param), the parameters will be stuffed into // an array. In this case, the content of the 'fields' param of the // mysql callback is in theResults[1] var tables = theResults[0]; // create an array of promises resulting from another Q.ninvoke() // query call, chained to .then(). Note that then() expects a function, // so recordEntry() in fact builds and returns a new one-off function // for actually recording the entry (see recordEntry() impl. below) var tableDefinitionGetters = []; for (var i = 0; i < tables.length ; i++){ // I noticed in your original code that your Tables_in_[] did not // match your connection details ('mvc' vs 'test'), but the below // should work and is a more generalized solution var tableName = tables[i]['Tables_in_'+connectionInfo.database]; tableDefinitionGetters.push(Q.ninvoke(self.connection, 'query', 'SHOW CREATE TABLE ' + tableName) .then(recordEntry(tableName)) ); } // now that you have an array of promises, you can use Q.allSettled // to return a promise which will be settled (resolved or rejected) // when all of the promises in the array are settled. Q.all is similar, // but its promise will be rejected (immediately) if any promise in the // array is rejected. I tend to use allSettled() in most cases. return Q.allSettled(tableDefinitionGetters); }; function recordEntry (tableName){ return function(createTableQryResult){ self.backup += "DROP TABLE " + tableName + "\n\n"; self.backup += createTableQryResult[0][0]["Create Table"] + "\n\n"; }; }; function saveFile(){ // Q.denodeify return a promise-enabled version of a node-style function // the below is probably excessively terse with its immediate invocation return (Q.denodeify(require('fs').writeFile))(filename, self.backup); } // with the above all done, now you can actually make the magic happen, // starting with the promise-return Q.ninvoke to connect to the DB // note that the successive .then()s will be executed iff (if and only // if) the preceding item resolves successfully, .catch() will get // executed in the event of any upstream error, and finally() will // get executed no matter what. Q.ninvoke(this.connection, 'connect') .then(getTables) .then(doTableEntries) .then(saveFile) .then( function() {console.log('Success'); } ) .catch( function(err) {console.log('Something went awry', err); } ) .finally( function() {self.connection.destroy(); } ); }; var myConnection = { host : '127.0.0.1', user : 'root', password : 'root', database : 'test' }; // I have left this as constructor-based calling approach, but the // constructor just does it all so I just ignore the return value new MysqlBackup(myConnection,'./backup_test.txt');