Đoạn mã được viết thậm chí còn không đến được tệp lưu cho tôi. Có vẻ như có một số vấn đề. Không chắc đây có phải là mã thực hay một số thứ bị mất trong quá trình dán bản sao. Tuy nhiên, dựa trên những gì bạn có:
Một vấn đề lớn là bạn không bao giờ kết nối với cơ sở dữ liệu trong mã của mình bằng connect.connect ().
Mã bạn muốn chạy sau khi kết nối phải nằm trong lệnh gọi lại connection.connect (). ví dụ:
connection.connect(function (err, empty) {
if (err)
throw new Error ('Panic');
// if no error, we are off to the races...
}
Tuy nhiên, ngay cả khi bạn nhanh chóng cấu trúc lại mã của mình để bọc những dòng cuối cùng bên trong lệnh gọi lại kết nối đó, bạn vẫn sẽ gặp sự cố, bởi vì bạn đang phá hủy kết nối trước khi các lệnh gọi SQL khác nhau được thực hiện, vì vậy bạn sẽ muốn di chuyển mã thành một số loại gọi lại cuối cùng.
Ngay cả sau khi bạn làm điều đó, bạn vẫn sẽ có một tệp trống, bởi vì bạn đang gọi save_backup từ lệnh gọi lại 'SHOW TABLES' thay vì sau khi bạn đã thực sự điền nó thông qua lệnh gọi lại bên trong, nơi bạn nhận được câu lệnh CREATE TABLE và điền vào tài sản dự phòng.
Đây là cách viết lại mã tối thiểu sẽ thực hiện được những gì bạn đang có ý định. Một điều quan trọng cần lưu ý là "bộ đếm" quản lý thời điểm ghi tệp và đóng kết nối. Tôi sẽ thực hiện các thay đổi khác nếu đó là của tôi, bao gồm:
- Sử dụng 'self' thay vì 'me'
- Sử dụng vòng lặp for dạng số thay vì cú pháp for (... in ...)
- Việc có các lệnh gọi lại của riêng tôi không tuân theo quy ước của nút về (err, things)
- Một thay đổi đáng kể hơn là tôi sẽ viết lại điều này để sử dụng các lời hứa, vì làm như vậy có thể giúp bạn bớt buồn phiền vì sự nhầm lẫn vốn có với các lệnh gọi lại lồng nhau sâu sắc. Cá nhân tôi thích thư viện Q, nhưng có một số tùy chọn ở đây.
Hy vọng điều này sẽ hữu ích.
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){;});
});
Cập nhật:Nếu bạn tò mò, đây là một triển khai được nhận xét nhiều bằng cách sử dụng các lời hứa. Lưu ý rằng nếu không có chú thích giải thích các chức năng của thư viện lời hứa Q, nó có phần ngắn hơn phiên bản gốc và cũng cung cấp khả năng xử lý lỗi toàn diện hơn.
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');