NodeJS等待/异步与嵌套MySQL查询

时间:2018-12-27 12:26:47

标签: mysql node.js asynchronous

我需要有关此代码的帮助:

var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";

async function checkIfUserCodeExist() {
  connection.promise().query(sqlCheckIfExist)
    .then(([rows, fields]) => {
    if (rows == 0) {
      console.log("Non esiste!")
      return res.send(JSON.stringify({
        "status": 500,
        "response": "codeNotExist"
      }));
    }
    checkIfCodeIsSameAsMine()
    console.log("Esiste!")
    console.log(rows[0].my_refer);
  })
    .catch(console.log)
    .then(() => connection.end());
}

async function checkIfCodeIsSameAsMine() {
  connection.promise().query(sqlCodeCheckSameAsMine)
    .then(([rows, fields]) => {
    if (rows == friendReferCode) {
      console.log("Codice uguale!")
      return res.send(JSON.stringify({
        "status": 500,
        "response": "sameCodeAsMine"
      }));
    }
    console.log("Codice non uguale!")
  })
    .catch(console.log)
    .then(() => connection.end());
}

checkIfUserCodeExist()

我以这种方式建立连接:

app.use(function(req, res, next) {
  global.connection = mysql.createConnection({
    host: 'xx',
    user: 'xx',
    password: 'xx',
    database: 'xx'
  });
  connection.connect();
  next();
});

我不明白一件事: 如何调用嵌套查询?当我检查checkIfUserCodeExist()函数中是否行== 0时,如果它为false,我会调用checkIfCodeIsSameAsMine(),但出现此错误:

Error: Can't add new command when connection is in closed state
at Connection._addCommandClosedState (/usr/myserver/node_modules/mysql2/lib/connection.js:135:17)
at Connection.end (/usr/myserver/node_modules/mysql2/lib/connection.js:836:26)
at connection.promise.query.then.catch.then (/usr/myserver/addReferFriend.js:45:31)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)

我该如何解决?

我在此处发布完整文件:

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.post('/', function(req, res, next) {
    var uid = req.body.uid;
    var friendReferCode = req.body.friendReferCode;

    var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";
async function checkIfUserCodeExist() {
    connection.promise().query(sqlCheckIfExist)
    .then( ([rows,fields]) => {
            if (rows == 0) {
                console.log("Non esiste!")
                return res.send(JSON.stringify({"status": 500,"response": "codeNotExist"}));
            }
            checkIfCodeIsSameAsMine()
            console.log("Esiste!")
            console.log(rows[0].my_refer);
    })
    .catch(console.log)
    .then( () => connection.end());
    }

    async function checkIfCodeIsSameAsMine() {
        connection.promise().query(sqlCodeCheckSameAsMine)
        .then( ([rows,fields]) => {
                if (rows == friendReferCode) {
                    console.log("Codice uguale!")
                    return res.send(JSON.stringify({"status": 500,"response": "sameCodeAsMine"}));
                }
                console.log("Codice non uguale!")
        })
        .catch(console.log)
        .then( () => connection.end());
        }

checkIfUserCodeExist()
});

module.exports = router;

谢谢!

3 个答案:

答案 0 :(得分:1)

这可能是因为您在 checkIfUserCodeExist 函数的结尾处终止了连接删除以下行,我认为它会起作用:

connection.end()

或者您每次要创建和打开方法时都想打开和关闭它,它将在进行任何数据库查询之前返回新的连接并调用它。例如:

 function getMysqlConnection() {
     const connection = mysql.createConnection({
         host: 'xx',
         user: 'xx',
         password: 'xx',
         database: 'xx'
     });
     connection.connect();
     return connection;
 }

 var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
 var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";
 async function checkIfUserCodeExist() {
     const connection = getMysqlConnection();
     connection.promise().query(sqlCheckIfExist)
         .then(([rows, fields]) => {
             if (rows == 0) {
                 console.log("Non esiste!")
                 return res.send(JSON.stringify({ "status": 500, "response": "codeNotExist" }));
             }
             checkIfCodeIsSameAsMine()
             console.log("Esiste!")
             console.log(rows[0].my_refer);
         })
         .catch(console.log)
         .then(() => connection.end());
 }

 async function checkIfCodeIsSameAsMine() {
     const connection = getMysqlConnection();
     connection.promise().query(sqlCodeCheckSameAsMine)
         .then(([rows, fields]) => {
             if (rows == friendReferCode) {
                 console.log("Codice uguale!")
                 return res.send(JSON.stringify({ "status": 500, "response": "sameCodeAsMine" }));
             }
             console.log("Codice non uguale!")
         })
         .catch(console.log)
         .then(() => connection.end());
 }

 checkIfUserCodeExist()

答案 1 :(得分:1)

您的程序中有多个问题需要更新。

首先,您不得使用全局变量来存储每个请求的数据库连接。如果两个请求同时到达,那么一个请求将覆盖创建的其他请求的connection,因此您可能会对两个请求使用相同的连接,并且/或者您不会关闭其中一个连接在悬空的连接中,在最坏的情况下可能会使您的应用程序无响应。

要解决该问题,您必须通过与请求对象的连接:

app.use(async function(req, res, next) {
  try {
    if( req.dbConnection ) {
      // ensure that req.dbConnection was not set already by another middleware
      throw new Error('req.dbConnection was already set')
    }

    let connection = mysql.createConnection({
      host: 'xx',
      user: 'xx',
      password: 'xx',
      database: 'xx'
    });

    res.on("finish", function() {
      // end the connection after the resonponse was send
      req.dbConnection.end()
    });

    // assign a promise base version of connection to request
    req.dbConnection = connection.promise()

    // wait for the connection to be established
    await connection.connect();
    next();
  } catch(err) {
    next(err);
  }
});

要访问每个请求定义的连接,您可以执行以下操作:

app.get('/', async function(req, res, next) {
   try {
     await checkIfUserCodeExist(req.dbConnection)

     // so something here after `checkIfUserCodeExist` finished
   }  catch(err) {
     next(err); // if an error occured pass it to the next
   }
})

async是与await一起使用的,如果您在函数主体中没有await,则在该函数之前不需要async

如果函数主体中没有await,则需要从函数中返回Promise链,以便调用者可以等待函数完成:

function checkIfUserCodeExist(connection) {
  return connection.query(sqlCheckIfExist)
    .then(([rows, fields]) => {
      if (rows == 0) {
        console.log("Non esiste!")

        return res.send(JSON.stringify({
          "status": 500,
          "response": "codeNotExist"
        }));
      }
      console.log("Esiste!")
      console.log(rows[0].my_refer);
      return  checkIfCodeIsSameAsMine(connection)
    })
}

function checkIfCodeIsSameAsMine(connection) {
  return connection.query(sqlCodeCheckSameAsMine)
    .then(([rows, fields]) => {
      if (rows == friendReferCode) {
        console.log("Codice uguale!")
        return res.send(JSON.stringify({
          "status": 500,
          "response": "sameCodeAsMine"
        }));
      }
      console.log("Codice non uguale!")
    })
}

如果您想使用async,它将看起来像这样:

async function checkIfUserCodeExist(connection) {
  let [rows, fields] = await connection.query(sqlCheckIfExist)

  if (rows == 0) {
    console.log("Non esiste!")
    return res.send(JSON.stringify({
      "status": 500,
      "response": "codeNotExist"
    }));
  }

  await checkIfCodeIsSameAsMine()

  console.log("Esiste!")
  console.log(rows[0].my_refer);
}

async function checkIfCodeIsSameAsMine(connection) {
  let [rows, fields] = await connection.query(sqlCodeCheckSameAsMine)

  if (rows == friendReferCode) {
    console.log("Codice uguale!")
    return res.send(JSON.stringify({
      "status": 500,
      "response": "sameCodeAsMine"
    }));
  }

  console.log("Codice non uguale!")
}

您应避免使用以下内容:

return res.send(JSON.stringify({
  "status": 500,
  "response": "codeNotExist"
}));

相反,您会抛出一个自定义错误,例如:

throw new CustomError(500, "codeNotExist")

并且有一个错误的中间件:

app.use(function(err, req, res, next) {
  return res.send({
    "status": err.status,
    "response": err.message
  });
})

因此,您只有一个地方可以创建错误响应,并且可以在需要时(例如,添加一些其他日志记录。

编辑(以匹配更新的问题)

/* GET users listing. */
router.post('/', function(req, res, next) {
  var uid = req.body.uid;
  var friendReferCode = req.body.friendReferCode;

  var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
  var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";

  function checkIfUserCodeExist() {
    return req.dbConnection.query(sqlCheckIfExist)
      .then(([rows, fields]) => {
        if (rows == 0) {
          console.log("Non esiste!")

          return res.send(JSON.stringify({
            "status": 500,
            "response": "codeNotExist"
          }));
        }
        console.log("Esiste!")
        console.log(rows[0].my_refer);
        return checkIfCodeIsSameAsMine(connection)
      })
  }

  function checkIfCodeIsSameAsMine() {
    return req.dbConnection.query(sqlCodeCheckSameAsMine)
      .then(([rows, fields]) => {
        if (rows == friendReferCode) {
          console.log("Codice uguale!")
          return res.send(JSON.stringify({
            "status": 500,
            "response": "sameCodeAsMine"
          }));
        }
        console.log("Codice non uguale!")
      })
  }

  checkIfUserCodeExist()
   .catch(next)
});

答案 2 :(得分:0)

好的,您的代码存在多个问题。我将首先解决您的特定问题,然后再提供一些其他提示。 :)

您的问题在于此逻辑内:

connection.promise().query(sqlCheckIfExist)
    .then(([rows, fields]) => {
    // some code 

    checkIfCodeIsSameAsMine()

   // some code
  })
    .catch(console.log)
    .then(() => connection.end());

checkIfCodeIsSameAsMine()函数是异步的。因此,此代码链中发生的事情是,您调用checkIfCodeIsSameAsMine(),但您不等待其结果,然后立即跳转到关闭数据库的最后一个then()连接。因此,从本质上讲,在关闭连接后,在 中执行在checkIfCodeIsSameAsMine()中执行的代码。

您应该return checkIfCodeIsSameAsMine()。这样,您将等待该函数的Promise响应。

现在我还有其他要点。

首先,"SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";不良。您会将应用程序暴露给SQL注入之类的漏洞。您应该通过某些解析功能对SQL查询中的动态值进行转义。通常,这是通过ORM(您使用的connection())完成的。

第二,如果您使用async功能,则使用各自的await功能。像这样:

async function checkIfUserCodeExist() {
  let rows, fields;

  try {
    [rows, fields] = await connection.promise().query(sqlCheckIfExist);
  } catch (err) {
    console.log(err);
  }
  if (rows == 0) {
    console.log("Non esiste!");
    return res.send(JSON.stringify({
      "status": 500,
      "response": "codeNotExist"
    }));
  }
  console.log("Esiste!");
  console.log(rows[0].my_refer);

  let result;
  try {
    result = await checkIfCodeIsSameAsMine();
  } catch (err) {
    console.log(err);
  }

  // do something with "result" if you wish

  await connection.end();
}